<!--
Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.

SPDX-License-Identifier: curl
-->

# Alt-Svc

curl features support for the Alt-Svc: HTTP header.

## Enable Alt-Svc in build

`./configure --enable-alt-svc`

(enabled by default since 7.73.0)

## Standard

[RFC 7838](https://datatracker.ietf.org/doc/html/rfc7838)

# Alt-Svc cache file format

This is a text based file with one line per entry and each line consists of nine
space separated fields.

## Example

    h2 quic.tech 8443 h3-22 quic.tech 8443 "20190808 06:18:37" 0 0

## Fields

1. The ALPN id for the source origin
2. The hostname for the source origin
3. The port number for the source origin
4. The ALPN id for the destination host
5. The hostname for the destination host
6. The port number for the destination host
7. The expiration date and time of this entry within double quotes.
   The date format is "YYYYMMDD HH:MM:SS" and the time zone is GMT.
8. Boolean (1 or 0) if "persist" was set for this entry
9. Integer priority value (not currently used)

If the hostname is an IPv6 numerical address, it is stored with brackets such
as `[::1]`.
<!--
Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.

SPDX-License-Identifier: curl
-->

libcurl bindings
================

Creative people have written bindings or interfaces for various environments
and programming languages. Using one of these allows you to take advantage of
curl powers from within your favorite language or system.

This is a list of all known interfaces as of this writing.

The bindings listed below are not part of the curl/libcurl distribution
archives, but must be downloaded and installed separately.

<!-- markdown-link-check-disable -->

[Ada95](https://web.archive.org/web/20070403105909/www.almroth.com/adacurl/index.html) Written by Andreas Almroth

[Basic](https://scriptbasic.com/) ScriptBasic bindings written by Peter Verhas

C++: [curlpp](https://github.com/jpbarrette/curlpp) Written by Jean-Philippe Barrette-LaPierre,
[curlcpp](https://github.com/JosephP91/curlcpp) by Giuseppe Persico and
[C++ Requests](https://github.com/libcpr/cpr) by Huu Nguyen

[Ch](https://chcurl.sourceforge.net/) Written by Stephen Nestinger and Jonathan Rogado

Cocoa: [BBHTTP](https://github.com/biasedbit/BBHTTP) written by Bruno de Carvalho
[curlhandle](https://github.com/karelia/curlhandle) Written by Dan Wood

Clojure: [clj-curl](https://github.com/lsevero/clj-curl) by Lucas Severo

[D](https://dlang.org/library/std/net/curl.html) Written by Kenneth Bogert

[Delphi](https://github.com/Mercury13/curl4delphi) Written by Mikhail Merkuryev

[Dylan](https://dylanlibs.sourceforge.net/) Written by Chris Double

[Eiffel](https://iron.eiffel.com/repository/20.11/package/ABEF6975-37AC-45FD-9C67-52D10BA0669B) Written by Eiffel Software

[Euphoria](https://web.archive.org/web/20050204080544/rays-web.com/eulibcurl.htm) Written by Ray Smith

[Falcon](https://web.archive.org/web/20240130001835/www.falconpl.org/project_docs/curl/)

[Ferite](https://web.archive.org/web/20150102192018/ferite.org/) Written by Paul Querna

[Fortran](https://github.com/interkosmos/fortran-curl) Written by Philipp Engel

[Gambas](https://gambaswiki.org/website/en/main.html)

[glib/GTK+](https://web.archive.org/web/20100526203452/atterer.net/glibcurl) Written by Richard Atterer

Go: [go-curl](https://github.com/andelf/go-curl) by ShuYu Wang

[Guile](https://github.com/spk121/guile-curl) Written by Michael L. Gran

[Harbour](https://github.com/vszakats/hb/tree/main/contrib/hbcurl) Written by Viktor Szakats

[Haskell](https://hackage.haskell.org/package/curl) Written by Galois, Inc

[Hollywood](https://www.hollywood-mal.com/download.html) hURL by Andreas Falkenhahn

[Java](https://github.com/covers1624/curl4j)

[Julia](https://github.com/JuliaWeb/LibCURL.jl) Written by Amit Murthy

[Katipo](https://github.com/puzza007/katipo) is an Erlang HTTP library around libcurl.

[Lisp](https://common-lisp.net/project/cl-curl/) Written by Liam Healy

[LibQurl](https://github.com/Qriist/LibQurl) a feature-rich AutoHotKey v2 (AHKv2) wrapper around libcurl.

Lua: [luacurl](https://web.archive.org/web/20201205052437/luacurl.luaforge.net/) by Alexander Marinov, [Lua-curl](https://github.com/Lua-cURL) by Jürgen Hötzel

[Mono](https://web.archive.org/web/20070606064500/forge.novell.com/modules/xfmod/project/?libcurl-mono) Written by Jeffrey Phillips

[.NET](https://sourceforge.net/projects/libcurl-net/) libcurl-net by Jeffrey Phillips

[Nim](https://nimble.directory/pkg/libcurl) wrapper for libcurl

[node.js](https://github.com/JCMais/node-libcurl) node-libcurl by Jonathan Cardoso Machado

[Object-Pascal](https://web.archive.org/web/20020610214926/www.tekool.com/opcurl) Free Pascal, Delphi and Kylix binding written by Christophe Espern.

[OCaml](https://opam.ocaml.org/packages/ocurl/) Written by Lars Nilsson and ygrek

[Pascal](https://web.archive.org/web/20030804091414/houston.quik.com/jkp/curlpas/) Free Pascal, Delphi and Kylix binding written by Jeffrey Pohlmeyer.

Perl: [WWW::Curl](https://github.com/szbalint/WWW--Curl) Maintained by Cris
Bailiff and Bálint Szilakszi,
[perl6-net-curl](https://github.com/azawawi/perl6-net-curl) by Ahmad M. Zawawi
[NET::Curl](https://metacpan.org/pod/Net::Curl) by Przemyslaw Iskra

[PHP](https://php.net/curl) Originally written by Sterling Hughes

[PostgreSQL](https://github.com/pramsey/pgsql-http) - HTTP client for PostgreSQL

[PostgreSQL](https://github.com/RekGRpth/pg_curl) - curl client for PostgreSQL

[PureBasic](https://web.archive.org/web/20250325015028/www.purebasic.com/documentation/http/index.html) uses libcurl in its "native" HTTP subsystem

[Python](https://github.com/pycurl/pycurl) PycURL by Kjetil Jacobsen

[Python](https://pypi.org/project/pymcurl/) mcurl by Ganesh Viswanathan

[Q](https://q-lang.sourceforge.net/) The libcurl module is part of the default install

[R](https://cran.r-project.org/package=curl)

[Rexx](https://rexxcurl.sourceforge.net/) Written by Mark Hessling

[Ring](https://ring-lang.github.io/doc1.24/libcurl.html) RingLibCurl by Mahmoud Fayed

RPG, support for ILE/RPG on OS/400 is included in source distribution

Ruby: [curb](https://github.com/taf2/curb) written by Ross Bamford,
[ruby-curl-multi](https://github.com/kball/curl_multi.rb) by Kristjan Petursson and Keith Rarick

[Rust](https://github.com/alexcrichton/curl-rust) curl-rust - by Carl Lerche

[Scheme](https://metapaper.net/lisovsky/web/curl/) Bigloo binding by Kirill Lisovsky

[Scilab](https://help.scilab.org/docs/current/fr_FR/getURL.html) binding by Sylvestre Ledru

[S-Lang](https://www.jedsoft.org/slang/modules/curl.html) by John E Davis

[Smalltalk](https://www.squeaksource.com/CurlPlugin/) Written by Danil Osipchuk

[SP-Forth](https://sourceforge.net/p/spf/spf/ci/master/tree/devel/~ac/lib/lin/curl/) Written by Andrey Cherezov

[SPL](https://web.archive.org/web/20210203022158/www.clifford.at/spl/spldoc/curl.html) Written by Clifford Wolf

[Tcl](https://web.archive.org/web/20160826011806/mirror.yellow5.com/tclcurl/) Tclcurl by Andrés García

[Vibe](https://github.com/ttytm/vibe) HTTP requests through libcurl in V

[Visual Basic](https://sourceforge.net/projects/libcurl-vb/) libcurl-vb by Jeffrey Phillips

[Visual Foxpro](https://web.archive.org/web/20130730181523/www.ctl32.com.ar/libcurl.asp) by Carlos Alloatti

[wxWidgets](https://wxcode.sourceforge.net/components/wxcurl/) Written by Casey O'Donnell

[XBLite](https://web.archive.org/web/20060426150418/perso.wanadoo.fr/xblite/libraries.html) Written by David Szafranski

[Xojo](https://github.com/charonn0/RB-libcURL) Written by Andrew Lambert

[Zig](https://github.com/jiacai2050/zig-curl) Written by Jiacai Liu, both easy and multi API are supported.
<!--
Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.

SPDX-License-Identifier: curl
-->

# No curl bug bounty

The curl project does not offer any rewards for reported bugs or
vulnerabilities. We do not aid security researchers to get such rewards for
curl problems from other sources.

A bug bounty gives people too strong incentives to find and make up "problems"
in bad faith that cause overload and abuse.

We still appreciate and value valid vulnerability reports.
<!--
Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.

SPDX-License-Identifier: curl
-->

# BUGS

## There are still bugs

curl and libcurl keep being developed. Adding features and changing code
means that bugs sneak in, no matter how hard we try to keep them out.

Of course there are lots of bugs left. Not to mention misfeatures.

To help us make curl the stable and solid product we want it to be, we need
bug reports and bug fixes.

## Where to report

If you cannot fix a bug yourself and submit a fix for it, try to report an as
detailed report as possible to a curl mailing list to allow one of us to have
a go at a solution. You can optionally also submit your problem in
[curl's bug tracking system](https://github.com/curl/curl/issues).

Please read the rest of this document below first before doing that.

If you feel you need to ask around first, find a suitable
[mailing list](https://curl.se/mail/) and post your questions there.

## Security bugs

If you find a bug or problem in curl or libcurl that you think has a security
impact, for example a bug that can put users in danger or make them
vulnerable if the bug becomes public knowledge, then please report that bug
using our security development process.

Security related bugs or bugs that are suspected to have a security impact,
should be reported [privately](https://curl.se/dev/vuln-disclosure.html).

This ensures that the report reaches the curl security team so that they first
can deal with the report away from the public to minimize the harm and impact
it has on existing users out there who might be using the vulnerable versions.

The curl project's process for handling security related issues is
[documented separately](https://curl.se/dev/secprocess.html).

## What to report

When reporting a bug, you should include all information to help us
understand what is wrong, what you expected to happen and how to repeat the
bad behavior. You therefore need to tell us:

- your operating system's name and version number

- what version of curl you are using (`curl -V` is fine)

- versions of the used libraries that libcurl is built to use

- what URL you were working with (if possible), at least which protocol

and anything and everything else you think matters. Tell us what you expected
to happen, tell us what did happen, tell us how you could make it work
another way. Dig around, try out, test. Then include all the tiny bits and
pieces in your report. You benefit from this yourself, as it enables us to
help you quicker and more accurately.

Since curl deals with networks, it often helps us if you include a protocol
debug dump with your bug report. The output you get by using the `-v` or
`--trace` options.

If curl crashed, causing a core dump (in Unix), there is hardly any use to
send that huge file to anyone of us. Unless we have the same system setup as
you, we cannot do much with it. Instead, we ask you to get a stack trace and
send that (much smaller) output to us instead.

The address and how to subscribe to the mailing lists are detailed in the
`MANUAL.md` file.

## libcurl problems

When you have written your own application with libcurl to perform transfers,
it is even more important to be specific and detailed when reporting bugs.

Tell us the libcurl version and your operating system. Tell us the name and
version of all relevant sub-components like for example the SSL library
you are using and what name resolving your libcurl uses. If you use SFTP or
SCP, the libssh2 version is relevant etc.

Showing us a real source code example repeating your problem is the best way
to get our attention and it greatly increases our chances to understand your
problem and to work on a fix (if we agree it truly is a problem).

Lots of problems that appear to be libcurl problems are instead abuses of the
libcurl API or other malfunctions in your applications. It is advised that you
run your problematic program using a memory debug tool like valgrind or
similar before you post memory-related or "crashing" problems to us.

## Who fixes the problems

If the problems or bugs you describe are considered to be bugs, we want to
have the problems fixed.

There are no developers in the curl project that are paid to work on bugs.
All developers that take on reported bugs do this on a voluntary basis. We do
it out of an ambition to keep curl and libcurl excellent products and out of
pride.

Please do not assume that you can lump over something to us and it then
automatically gets fixed after some given time. Most often we need feedback
and help to understand what you have experienced and how to repeat a problem.
Then we may only be able to assist YOU to debug the problem and to track down
the proper fix.

We get reports from many people every month and each report can take a
considerable amount of time to really go to the bottom with.

## How to get a stack trace

First, you must make sure that you compile all sources with `-g` and that you
do not 'strip' the final executable. Try to avoid optimizing the code as well,
remove `-O`, `-O2` etc from the compiler options.

Run the program until it cores.

Run your debugger on the core file, like `<debugger> curl core`. `<debugger>`
should be replaced with the name of your debugger, in most cases that is
`gdb`, but `dbx` and others also occur.

When the debugger has finished loading the core file and presents you a
prompt, enter `where` (without quotes) and press return.

The list that is presented is the stack trace. If everything worked, it is
supposed to contain the chain of functions that were called when curl
crashed. Include the stack trace with your detailed bug report, it helps a
lot.

## Bugs in libcurl bindings

There are of course bugs in libcurl bindings. You should then primarily
approach the team that works on that particular binding and see what you can
do to help them fix the problem.

If you suspect that the problem exists in the underlying libcurl, then please
convert your program over to plain C and follow the steps outlined above.

## Bugs in old versions

The curl project typically releases new versions every other month, and we
fix several hundred bugs per year. For a huge table of releases, number of
bug fixes and more, see: https://curl.se/docs/releases.html

The developers in the curl project do not have bandwidth or energy enough to
maintain several branches or to spend much time on hunting down problems in
old versions when chances are we already fixed them or at least that they have
changed nature and appearance in later versions.

When you experience a problem and want to report it, you really SHOULD
include the version number of the curl you are using when you experience the
issue. If that version number shows us that you are using an out-of-date curl,
you should also try out a modern curl version to see if the problem persists
or how/if it has changed in appearance.

Even if you cannot immediately upgrade your application/system to run the
latest curl version, you can most often at least run a test version or
experimental build or similar, to get this confirmed or not.

At times people insist that they cannot upgrade to a modern curl version, they
only "want the bug fixed". That is fine, but do not count on us spending many
cycles on trying to identify which single commit, if that is even possible,
that at some point in the past fixed the problem you are now experiencing.

Security wise, it is almost always a bad idea to lag behind the current curl
versions by a lot. We keep discovering and reporting security problems
over time see you can see in
[this table](https://curl.se/docs/vulnerabilities.html)

# Bug fixing procedure

## What happens on first filing

When a new issue is posted in the issue tracker or on the mailing list, the
team of developers first needs to see the report. Maybe they took the day off,
maybe they are off in the woods hunting. Have patience. Allow at least a few
days before expecting someone to have responded.

In the issue tracker, you can expect that some labels are set on the issue to
help categorize it.

## First response

If your issue/bug report was not perfect at once (and few are), chances are
that someone asks follow-up questions. Which version did you use? Which
options did you use? How often does the problem occur? How can we reproduce
this problem? Which protocols does it involve? Or perhaps much more specific
and deep diving questions. It all depends on your specific issue.

You should then respond to these follow-up questions and provide more info
about the problem, so that we can help you figure it out. Or maybe you can
help us figure it out. An active back-and-forth communication is important
and the key for finding a cure and landing a fix.

## Not reproducible

We may require further work from you who actually see or experience the
problem if we cannot reproduce it and cannot understand it even after having
gotten all the info we need and having studied the source code over again.

## Unresponsive

If the problem have not been understood or reproduced, and there is nobody
responding to follow-up questions or questions asking for clarifications or
for discussing possible ways to move forward with the task, we take that as a
strong suggestion that the bug is unimportant.

Unimportant issues are closed as inactive sooner or later as they cannot be
fixed. The inactivity period (waiting for responses) should not be shorter
than two weeks but may extend months.

## Lack of time/interest

Bugs that are filed and are understood can unfortunately end up in the
"nobody cares enough about it to work on it" category. Such bugs are
perfectly valid problems that *should* get fixed but apparently are not. We
try to mark such bugs as `KNOWN_BUGS material` after a time of inactivity and
if no activity is noticed after yet some time those bugs are added to the
`KNOWN_BUGS` document and are closed in the issue tracker.

## `KNOWN_BUGS`

This is a list of known bugs. Bugs we know exist and that have been pointed
out but that have not yet been fixed. The reasons for why they have not been
fixed can involve anything really, but the primary reason is that nobody has
considered these problems to be important enough to spend the necessary time
and effort to have them fixed.

The `KNOWN_BUGS` items are always up for grabs and we love the ones who bring
one of them back to life and offer solutions to them.

The `KNOWN_BUGS` document has a sibling document known as `TODO`.

## `TODO`

Issues that are filed or reported that are not really bugs but more missing
features or ideas for future improvements and so on are marked as
*enhancement* or *feature-request* and get added to the `TODO` document and
the issues are closed. We do not keep TODO items open in the issue tracker.

The `TODO` document is full of ideas and suggestions of what we can add or
fix one day. You are always encouraged and free to grab one of those items and
take up a discussion with the curl development team on how that could be
implemented or provided in the project so that you can work on ticking it odd
that document.

If an issue is rather a bug and not a missing feature or functionality, it is
listed in `KNOWN_BUGS` instead.

## Closing off stalled bugs

The [issue and pull request trackers](https://github.com/curl/curl) only hold
"active" entries open (using a non-precise definition of what active actually
is, but they are at least not completely dead). Those that are abandoned or
in other ways dormant are closed and sometimes added to `TODO` and
`KNOWN_BUGS` instead.

This way, we only have "active" issues open on GitHub. Irrelevant issues and
pull requests do not distract developers or casual visitors.
<!--
Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.

SPDX-License-Identifier: curl
-->

## curl cipher options

A TLS handshake involves many parameters which take part in the negotiation
between client and server in order to agree on the TLS version and set of
algorithms to use for a connection.

What has become known as a "cipher" or better "cipher suite" in TLS
are names for specific combinations of
[key exchange](https://en.wikipedia.org/wiki/Key_exchange),
[bulk encryption](https://en.wikipedia.org/wiki/Link_encryption),
[message authentication code](https://en.wikipedia.org/wiki/Message_authentication_code)
and with TLSv1.3 the
[authenticated encryption](https://en.wikipedia.org/wiki/Authenticated_encryption).
In addition, there are other parameters that influence the TLS handshake, like
[DHE](https://en.wikipedia.org/wiki/Diffie%e2%80%93Hellman_key_exchange) "groups"
and [ECDHE](https://en.wikipedia.org/wiki/Elliptic-curve_Diffie%e2%80%93Hellman)
with its "curves".

### History

curl's way of letting users configure these settings closely followed OpenSSL
in its API. TLS learned new parameters, OpenSSL added new API functions and
curl added command line options.

Several other TLS backends followed the OpenSSL approach, more or less closely,
and curl maps the command line options to these TLS backends. Some TLS
backends do not support all of it and command line options are either
ignored or lead to an error.

Many examples below show the OpenSSL-like use of these options. GnuTLS
however chose a different approach. These are described in a separate
section further below.

## ciphers, the OpenSSL way

With curl's option
[`--tls13-ciphers`](https://curl.se/docs/manpage.html#--tls13-ciphers)
or
[`CURLOPT_TLS13_CIPHERS`](https://curl.se/libcurl/c/CURLOPT_TLS13_CIPHERS.html)
users can control which cipher suites to consider when negotiating TLS 1.3
connections. With option
[`--ciphers`](https://curl.se/docs/manpage.html#--ciphers)
or
[`CURLOPT_SSL_CIPHER_LIST`](https://curl.se/libcurl/c/CURLOPT_SSL_CIPHER_LIST.html)
users can control which cipher suites to consider when negotiating
TLS 1.2 (1.1, 1.0) connections.

By default, curl may negotiate TLS 1.3 and TLS 1.2 connections, so the cipher
suites considered when negotiating a TLS connection are a union of the TLS 1.3
and TLS 1.2 cipher suites. If you want curl to consider only TLS 1.3 cipher
suites for the connection, you have to set the minimum TLS version to 1.3 by
using [`--tlsv1.3`](https://curl.se/docs/manpage.html#--tlsv13)
or [`CURLOPT_SSLVERSION`](https://curl.se/libcurl/c/CURLOPT_SSLVERSION.html)
with `CURL_SSLVERSION_TLSv1_3`.

Both the TLS 1.3 and TLS 1.2 cipher options expect a list of cipher suites
separated by colons (`:`). This list is parsed opportunistically, cipher suites
that are not recognized or implemented are ignored. As long as there is at
least one recognized cipher suite in the list, the list is considered valid.

For both the TLS 1.3 and TLS 1.2 cipher options, the order in which the
cipher suites are specified determine the preference of them. When negotiating
a TLS connection the server picks a cipher suite from the intersection of the
cipher suites supported by the server and the cipher suites sent by curl. If
the server is configured to honor the client's cipher preference, the first
common cipher suite in the list sent by curl is chosen.

### TLS 1.3 cipher suites

Setting TLS 1.3 cipher suites is supported by curl with
OpenSSL (1.1.1+, curl 7.61.0+), LibreSSL (3.4.1+, curl 8.3.0+),
wolfSSL (curl 8.10.0+) and mbedTLS (3.6.0+, curl 8.10.0+).

The list of cipher suites that can be used for the `--tls13-ciphers` option:

```
TLS_AES_128_GCM_SHA256
TLS_AES_256_GCM_SHA384
TLS_CHACHA20_POLY1305_SHA256
TLS_AES_128_CCM_SHA256
TLS_AES_128_CCM_8_SHA256
```

#### wolfSSL notes

In addition to above list the following cipher suites can be used:
`TLS_SM4_GCM_SM3` `TLS_SM4_CCM_SM3` `TLS_SHA256_SHA256` `TLS_SHA384_SHA384`.
Usage of these cipher suites is not recommended. (The last two cipher suites
are NULL ciphers, offering no encryption whatsoever.)

### TLS 1.2 (1.1, 1.0) cipher suites

Setting TLS 1.2 cipher suites is supported by curl with AWS-LC, BoringSSL,
LibreSSL, mbedTLS (curl 8.8.0+), OpenSSL, wolfSSL (curl 7.53.0+). Schannel
does not support setting cipher suites directly, but does support setting
algorithms (curl 7.61.0+), see Schannel notes below.

For TLS 1.2 cipher suites there are multiple naming schemes, the two most used
are with OpenSSL names (e.g. `ECDHE-RSA-AES128-GCM-SHA256`) and IANA names
(e.g. `TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256`). IANA names of TLS 1.2 cipher
suites look similar to TLS 1.3 cipher suite names, to distinguish them note
that TLS 1.2 names contain `_WITH_`, while TLS 1.3 names do not. When setting
TLS 1.2 cipher suites with curl it is recommended that you use OpenSSL names
as these are most widely recognized by the supported SSL backends.

The complete list of cipher suites that may be considered for the `--ciphers`
option is extensive, it consists of more than 300 ciphers suites. Nowadays,
most of them are discouraged, and support for a lot of them has been removed
from the various SSL backends, if ever implemented at all.

A shortened list (based on [recommendations by
Mozilla](https://wiki.mozilla.org/Security/Server_Side_TLS)) of cipher suites,
which are (mostly) supported by all SSL backends, that can be used for the
`--ciphers` option:

```
ECDHE-ECDSA-AES128-GCM-SHA256
ECDHE-RSA-AES128-GCM-SHA256
ECDHE-ECDSA-AES256-GCM-SHA384
ECDHE-RSA-AES256-GCM-SHA384
ECDHE-ECDSA-CHACHA20-POLY1305
ECDHE-RSA-CHACHA20-POLY1305
DHE-RSA-AES128-GCM-SHA256
DHE-RSA-AES256-GCM-SHA384
DHE-RSA-CHACHA20-POLY1305
ECDHE-ECDSA-AES128-SHA256
ECDHE-RSA-AES128-SHA256
ECDHE-ECDSA-AES128-SHA
ECDHE-RSA-AES128-SHA
ECDHE-ECDSA-AES256-SHA384
ECDHE-RSA-AES256-SHA384
ECDHE-ECDSA-AES256-SHA
ECDHE-RSA-AES256-SHA
DHE-RSA-AES128-SHA256
DHE-RSA-AES256-SHA256
AES128-GCM-SHA256
AES256-GCM-SHA384
AES128-SHA256
AES256-SHA256
AES128-SHA
AES256-SHA
DES-CBC3-SHA
```

See this [list](https://github.com/curl/curl/blob/master/docs/CIPHERS-TLS12.md)
for a complete list of TLS 1.2 cipher suites.

#### OpenSSL notes

In addition to specifying a list of cipher suites, OpenSSL also accepts a
format with specific cipher strings (like `TLSv1.2`, `AESGCM`, `CHACHA20`) and
`!`, `-` and `+` operators. Refer to the
[OpenSSL cipher documentation](https://docs.openssl.org/master/man1/openssl-ciphers/#cipher-list-format)
for further information on that format.

#### Schannel notes

Schannel does not support setting individual TLS 1.2 cipher suites directly.
It only allows the enabling and disabling of encryption algorithms. These are
in the form of `CALG_xxx`, see the [Schannel `ALG_ID`
documentation](https://learn.microsoft.com/windows/win32/seccrypto/alg-id)
for a list of these algorithms. Also, (since curl 7.77.0)
`SCH_USE_STRONG_CRYPTO` can be given to pass that flag to Schannel, lookup the
[documentation for the Windows version in
use](https://learn.microsoft.com/windows/win32/secauthn/cipher-suites-in-schannel)
to see how that affects the cipher suite selection. When not specifying the
`--ciphers` and `--tls13-ciphers` options curl passes this flag by default.

### Examples

```sh
curl \
  --tls13-ciphers TLS_AES_128_GCM_SHA256:TLS_CHACHA20_POLY1305_SHA256 \
  --ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:\
ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305 \
  https://example.com/
```

Restrict ciphers to `aes128-gcm` and `chacha20`. Works with OpenSSL, LibreSSL,
mbedTLS and wolfSSL.

```sh
curl \
  --tlsv1.3 \
  --tls-max 1.3 \
  --tls13-ciphers TLS_AES_128_GCM_SHA256:TLS_CHACHA20_POLY1305_SHA256 \
  https://example.com/
```

Restrict to only TLS 1.3 with `aes128-gcm` and `chacha20` ciphers. Works with
OpenSSL, LibreSSL, mbedTLS and wolfSSL.

```sh
curl \
  --ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:\
ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305 \
  https://example.com/
```

Restrict TLS 1.2 ciphers to `aes128-gcm` and `chacha20`, use default TLS 1.3
ciphers (if TLS 1.3 is available). Works with OpenSSL, LibreSSL, BoringSSL,
mbedTLS and wolfSSL.

## ciphers, the GnuTLS way

With GnuTLS, curl allows configuration of all TLS parameters via option
[`--ciphers`](https://curl.se/docs/manpage.html#--ciphers)
or
[`CURLOPT_SSL_CIPHER_LIST`](https://curl.se/libcurl/c/CURLOPT_SSL_CIPHER_LIST.html)
only. The option
[`--tls13-ciphers`](https://curl.se/docs/manpage.html#--tls13-ciphers)
or
[`CURLOPT_TLS13_CIPHERS`](https://curl.se/libcurl/c/CURLOPT_TLS13_CIPHERS.html)
is being ignored.

`--ciphers` is used to set the GnuTLS **priority string** in
the following way:

* When the set string starts with '+', '-' or '!' it is *appended* to the
  priority string libcurl itself generates (separated by ':'). This initial
  priority depends other settings such as CURLOPT_SSLVERSION(3) or if HTTP/3
  (QUIC) is being negotiated.
* Otherwise, the set string fully *replaces* the libcurl generated one. While
  giving full control to the application, the set priority needs to
  provide for everything the transfer may need to negotiate. Example: if
  the set priority only allows TLSv1.2, all HTTP/3 attempts fail.

Users may specify via `--ciphers` anything that GnuTLS supports: ciphers,
key exchange, MAC, compression, TLS versions, signature algorithms, groups,
elliptic curves, certificate types. In addition, GnuTLS has a variety of
other keywords that tweak its operations. Applications or a system
may define new alias names for priority strings that can then be used here.

Since the order of items in priority strings is significant, it makes no
sense for curl to puzzle other SSL options somehow together. `--ciphers`
is the single way to change priority.

### Examples

```sh
curl \
  --ciphers '-CIPHER_ALL:+AES-128-GCM:+CHACHA20-POLY1305' \
  https://example.com/
```

Restrict ciphers to `aes128-gcm` and `chacha20` in GnuTLS.

```sh
curl \
  --ciphers 'NORMAL:-VERS-ALL:+TLS1.3:-AES-256-GCM' \
  https://example.com/
```

Restrict to only TLS 1.3 without the `aes256-gcm` cipher.

```sh
curl \
  --ciphers 'NORMAL:-VERS-ALL:+TLS1.2:-CIPHER_ALL:+CAMELLIA-128-GCM' \
  https://example.com/
```

Restrict to only TLS 1.2 with the `CAMELLIA-128-GCM` cipher.

## Further reading

- [GnuTLS Priority Strings](https://gnutls.org/manual/html_node/Priority-Strings.html)
- [IANA cipher suites list](https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-4)
- [mbedTLS cipher suites reference](https://mbed-tls.readthedocs.io/projects/api/en/development/api/file/ssl__ciphersuites_8h/)
- [OpenSSL cipher suite names documentation](https://docs.openssl.org/master/man1/openssl-ciphers/#cipher-suite-names)
- [Schannel cipher suites documentation](https://learn.microsoft.com/windows/win32/secauthn/cipher-suites-in-schannel)
- [Wikipedia cipher suite article](https://en.wikipedia.org/wiki/Cipher_suite)
- [wolfSSL cipher support documentation](https://www.wolfssl.com/documentation/manuals/wolfssl/chapter04.html#cipher-support)
<!--
Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.

SPDX-License-Identifier: curl
-->

# TLS 1.2 cipher suites

| Id     | IANA name                                     | OpenSSL name                       | RFC                |
|--------|-----------------------------------------------|------------------------------------|--------------------|
| 0x0001 | TLS_RSA_WITH_NULL_MD5                         | NULL-MD5                           | [RFC5246]          |
| 0x0002 | TLS_RSA_WITH_NULL_SHA                         | NULL-SHA                           | [RFC5246]          |
| 0x0003 | TLS_RSA_EXPORT_WITH_RC4_40_MD5                | EXP-RC4-MD5                        | [RFC4346][RFC6347] |
| 0x0004 | TLS_RSA_WITH_RC4_128_MD5                      | RC4-MD5                            | [RFC5246][RFC6347] |
| 0x0005 | TLS_RSA_WITH_RC4_128_SHA                      | RC4-SHA                            | [RFC5246][RFC6347] |
| 0x0006 | TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5            | EXP-RC2-CBC-MD5                    | [RFC4346]          |
| 0x0007 | TLS_RSA_WITH_IDEA_CBC_SHA                     | IDEA-CBC-SHA                       | [RFC8996]          |
| 0x0008 | TLS_RSA_EXPORT_WITH_DES40_CBC_SHA             | EXP-DES-CBC-SHA                    | [RFC4346]          |
| 0x0009 | TLS_RSA_WITH_DES_CBC_SHA                      | DES-CBC-SHA                        | [RFC8996]          |
| 0x000A | TLS_RSA_WITH_3DES_EDE_CBC_SHA                 | DES-CBC3-SHA                       | [RFC5246]          |
| 0x000B | TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA          | EXP-DH-DSS-DES-CBC-SHA             | [RFC4346]          |
| 0x000C | TLS_DH_DSS_WITH_DES_CBC_SHA                   | DH-DSS-DES-CBC-SHA                 | [RFC8996]          |
| 0x000D | TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA              | DH-DSS-DES-CBC3-SHA                | [RFC5246]          |
| 0x000E | TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA          | EXP-DH-RSA-DES-CBC-SHA             | [RFC4346]          |
| 0x000F | TLS_DH_RSA_WITH_DES_CBC_SHA                   | DH-RSA-DES-CBC-SHA                 | [RFC8996]          |
| 0x0010 | TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA              | DH-RSA-DES-CBC3-SHA                | [RFC5246]          |
| 0x0011 | TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA         | EXP-DHE-DSS-DES-CBC-SHA            | [RFC4346]          |
| 0x0012 | TLS_DHE_DSS_WITH_DES_CBC_SHA                  | DHE-DSS-DES-CBC-SHA                | [RFC8996]          |
| 0x0013 | TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA             | DHE-DSS-DES-CBC3-SHA               | [RFC5246]          |
| 0x0014 | TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA         | EXP-DHE-RSA-DES-CBC-SHA            | [RFC4346]          |
| 0x0015 | TLS_DHE_RSA_WITH_DES_CBC_SHA                  | DHE-RSA-DES-CBC-SHA                | [RFC8996]          |
| 0x0016 | TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA             | DHE-RSA-DES-CBC3-SHA               | [RFC5246]          |
| 0x0017 | TLS_DH_anon_EXPORT_WITH_RC4_40_MD5            | EXP-ADH-RC4-MD5                    | [RFC4346][RFC6347] |
| 0x0018 | TLS_DH_anon_WITH_RC4_128_MD5                  | ADH-RC4-MD5                        | [RFC5246][RFC6347] |
| 0x0019 | TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA         | EXP-ADH-DES-CBC-SHA                | [RFC4346]          |
| 0x001A | TLS_DH_anon_WITH_DES_CBC_SHA                  | ADH-DES-CBC-SHA                    | [RFC8996]          |
| 0x001B | TLS_DH_anon_WITH_3DES_EDE_CBC_SHA             | ADH-DES-CBC3-SHA                   | [RFC5246]          |
| 0x001C |                                               | FZA-NULL-SHA                       |                    |
| 0x001D |                                               | FZA-FZA-CBC-SHA                    |                    |
| 0x001E | TLS_KRB5_WITH_DES_CBC_SHA                     | KRB5-DES-CBC-SHA                   | [RFC2712]          |
| 0x001F | TLS_KRB5_WITH_3DES_EDE_CBC_SHA                | KRB5-DES-CBC3-SHA                  | [RFC2712]          |
| 0x0020 | TLS_KRB5_WITH_RC4_128_SHA                     | KRB5-RC4-SHA                       | [RFC2712][RFC6347] |
| 0x0021 | TLS_KRB5_WITH_IDEA_CBC_SHA                    | KRB5-IDEA-CBC-SHA                  | [RFC2712]          |
| 0x0022 | TLS_KRB5_WITH_DES_CBC_MD5                     | KRB5-DES-CBC-MD5                   | [RFC2712]          |
| 0x0023 | TLS_KRB5_WITH_3DES_EDE_CBC_MD5                | KRB5-DES-CBC3-MD5                  | [RFC2712]          |
| 0x0024 | TLS_KRB5_WITH_RC4_128_MD5                     | KRB5-RC4-MD5                       | [RFC2712][RFC6347] |
| 0x0025 | TLS_KRB5_WITH_IDEA_CBC_MD5                    | KRB5-IDEA-CBC-MD5                  | [RFC2712]          |
| 0x0026 | TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA           | EXP-KRB5-DES-CBC-SHA               | [RFC2712]          |
| 0x0027 | TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA           | EXP-KRB5-RC2-CBC-SHA               | [RFC2712]          |
| 0x0028 | TLS_KRB5_EXPORT_WITH_RC4_40_SHA               | EXP-KRB5-RC4-SHA                   | [RFC2712][RFC6347] |
| 0x0029 | TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5           | EXP-KRB5-DES-CBC-MD5               | [RFC2712]          |
| 0x002A | TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5           | EXP-KRB5-RC2-CBC-MD5               | [RFC2712]          |
| 0x002B | TLS_KRB5_EXPORT_WITH_RC4_40_MD5               | EXP-KRB5-RC4-MD5                   | [RFC2712][RFC6347] |
| 0x002C | TLS_PSK_WITH_NULL_SHA                         | PSK-NULL-SHA                       | [RFC4785]          |
| 0x002D | TLS_DHE_PSK_WITH_NULL_SHA                     | DHE-PSK-NULL-SHA                   | [RFC4785]          |
| 0x002E | TLS_RSA_PSK_WITH_NULL_SHA                     | RSA-PSK-NULL-SHA                   | [RFC4785]          |
| 0x002F | TLS_RSA_WITH_AES_128_CBC_SHA                  | AES128-SHA                         | [RFC5246]          |
| 0x0030 | TLS_DH_DSS_WITH_AES_128_CBC_SHA               | DH-DSS-AES128-SHA                  | [RFC5246]          |
| 0x0031 | TLS_DH_RSA_WITH_AES_128_CBC_SHA               | DH-RSA-AES128-SHA                  | [RFC5246]          |
| 0x0032 | TLS_DHE_DSS_WITH_AES_128_CBC_SHA              | DHE-DSS-AES128-SHA                 | [RFC5246]          |
| 0x0033 | TLS_DHE_RSA_WITH_AES_128_CBC_SHA              | DHE-RSA-AES128-SHA                 | [RFC5246]          |
| 0x0034 | TLS_DH_anon_WITH_AES_128_CBC_SHA              | ADH-AES128-SHA                     | [RFC5246]          |
| 0x0035 | TLS_RSA_WITH_AES_256_CBC_SHA                  | AES256-SHA                         | [RFC5246]          |
| 0x0036 | TLS_DH_DSS_WITH_AES_256_CBC_SHA               | DH-DSS-AES256-SHA                  | [RFC5246]          |
| 0x0037 | TLS_DH_RSA_WITH_AES_256_CBC_SHA               | DH-RSA-AES256-SHA                  | [RFC5246]          |
| 0x0038 | TLS_DHE_DSS_WITH_AES_256_CBC_SHA              | DHE-DSS-AES256-SHA                 | [RFC5246]          |
| 0x0039 | TLS_DHE_RSA_WITH_AES_256_CBC_SHA              | DHE-RSA-AES256-SHA                 | [RFC5246]          |
| 0x003A | TLS_DH_anon_WITH_AES_256_CBC_SHA              | ADH-AES256-SHA                     | [RFC5246]          |
| 0x003B | TLS_RSA_WITH_NULL_SHA256                      | NULL-SHA256                        | [RFC5246]          |
| 0x003C | TLS_RSA_WITH_AES_128_CBC_SHA256               | AES128-SHA256                      | [RFC5246]          |
| 0x003D | TLS_RSA_WITH_AES_256_CBC_SHA256               | AES256-SHA256                      | [RFC5246]          |
| 0x003E | TLS_DH_DSS_WITH_AES_128_CBC_SHA256            | DH-DSS-AES128-SHA256               | [RFC5246]          |
| 0x003F | TLS_DH_RSA_WITH_AES_128_CBC_SHA256            | DH-RSA-AES128-SHA256               | [RFC5246]          |
| 0x0040 | TLS_DHE_DSS_WITH_AES_128_CBC_SHA256           | DHE-DSS-AES128-SHA256              | [RFC5246]          |
| 0x0041 | TLS_RSA_WITH_CAMELLIA_128_CBC_SHA             | CAMELLIA128-SHA                    | [RFC5932]          |
| 0x0042 | TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA          | DH-DSS-CAMELLIA128-SHA             | [RFC5932]          |
| 0x0043 | TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA          | DH-RSA-CAMELLIA128-SHA             | [RFC5932]          |
| 0x0044 | TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA         | DHE-DSS-CAMELLIA128-SHA            | [RFC5932]          |
| 0x0045 | TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA         | DHE-RSA-CAMELLIA128-SHA            | [RFC5932]          |
| 0x0046 | TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA         | ADH-CAMELLIA128-SHA                | [RFC5932]          |
| 0x0060 |                                               | EXP1024-RC4-MD5                    |                    |
| 0x0061 |                                               | EXP1024-RC2-CBC-MD5                |                    |
| 0x0062 |                                               | EXP1024-DES-CBC-SHA                |                    |
| 0x0063 |                                               | EXP1024-DHE-DSS-DES-CBC-SHA        |                    |
| 0x0064 |                                               | EXP1024-RC4-SHA                    |                    |
| 0x0065 |                                               | EXP1024-DHE-DSS-RC4-SHA            |                    |
| 0x0066 |                                               | DHE-DSS-RC4-SHA                    |                    |
| 0x0067 | TLS_DHE_RSA_WITH_AES_128_CBC_SHA256           | DHE-RSA-AES128-SHA256              | [RFC5246]          |
| 0x0068 | TLS_DH_DSS_WITH_AES_256_CBC_SHA256            | DH-DSS-AES256-SHA256               | [RFC5246]          |
| 0x0069 | TLS_DH_RSA_WITH_AES_256_CBC_SHA256            | DH-RSA-AES256-SHA256               | [RFC5246]          |
| 0x006A | TLS_DHE_DSS_WITH_AES_256_CBC_SHA256           | DHE-DSS-AES256-SHA256              | [RFC5246]          |
| 0x006B | TLS_DHE_RSA_WITH_AES_256_CBC_SHA256           | DHE-RSA-AES256-SHA256              | [RFC5246]          |
| 0x006C | TLS_DH_anon_WITH_AES_128_CBC_SHA256           | ADH-AES128-SHA256                  | [RFC5246]          |
| 0x006D | TLS_DH_anon_WITH_AES_256_CBC_SHA256           | ADH-AES256-SHA256                  | [RFC5246]          |
| 0x0080 |                                               | GOST94-GOST89-GOST89               |                    |
| 0x0081 |                                               | GOST2001-GOST89-GOST89             |                    |
| 0x0082 |                                               | GOST94-NULL-GOST94                 |                    |
| 0x0083 |                                               | GOST2001-NULL-GOST94               |                    |
| 0x0084 | TLS_RSA_WITH_CAMELLIA_256_CBC_SHA             | CAMELLIA256-SHA                    | [RFC5932]          |
| 0x0085 | TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA          | DH-DSS-CAMELLIA256-SHA             | [RFC5932]          |
| 0x0086 | TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA          | DH-RSA-CAMELLIA256-SHA             | [RFC5932]          |
| 0x0087 | TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA         | DHE-DSS-CAMELLIA256-SHA            | [RFC5932]          |
| 0x0088 | TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA         | DHE-RSA-CAMELLIA256-SHA            | [RFC5932]          |
| 0x0089 | TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA         | ADH-CAMELLIA256-SHA                | [RFC5932]          |
| 0x008A | TLS_PSK_WITH_RC4_128_SHA                      | PSK-RC4-SHA                        | [RFC4279][RFC6347] |
| 0x008B | TLS_PSK_WITH_3DES_EDE_CBC_SHA                 | PSK-3DES-EDE-CBC-SHA               | [RFC4279]          |
| 0x008C | TLS_PSK_WITH_AES_128_CBC_SHA                  | PSK-AES128-CBC-SHA                 | [RFC4279]          |
| 0x008D | TLS_PSK_WITH_AES_256_CBC_SHA                  | PSK-AES256-CBC-SHA                 | [RFC4279]          |
| 0x008E | TLS_DHE_PSK_WITH_RC4_128_SHA                  | DHE-PSK-RC4-SHA                    | [RFC4279][RFC6347] |
| 0x008F | TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA             | DHE-PSK-3DES-EDE-CBC-SHA           | [RFC4279]          |
| 0x0090 | TLS_DHE_PSK_WITH_AES_128_CBC_SHA              | DHE-PSK-AES128-CBC-SHA             | [RFC4279]          |
| 0x0091 | TLS_DHE_PSK_WITH_AES_256_CBC_SHA              | DHE-PSK-AES256-CBC-SHA             | [RFC4279]          |
| 0x0092 | TLS_RSA_PSK_WITH_RC4_128_SHA                  | RSA-PSK-RC4-SHA                    | [RFC4279][RFC6347] |
| 0x0093 | TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA             | RSA-PSK-3DES-EDE-CBC-SHA           | [RFC4279]          |
| 0x0094 | TLS_RSA_PSK_WITH_AES_128_CBC_SHA              | RSA-PSK-AES128-CBC-SHA             | [RFC4279]          |
| 0x0095 | TLS_RSA_PSK_WITH_AES_256_CBC_SHA              | RSA-PSK-AES256-CBC-SHA             | [RFC4279]          |
| 0x0096 | TLS_RSA_WITH_SEED_CBC_SHA                     | SEED-SHA                           | [RFC4162]          |
| 0x0097 | TLS_DH_DSS_WITH_SEED_CBC_SHA                  | DH-DSS-SEED-SHA                    | [RFC4162]          |
| 0x0098 | TLS_DH_RSA_WITH_SEED_CBC_SHA                  | DH-RSA-SEED-SHA                    | [RFC4162]          |
| 0x0099 | TLS_DHE_DSS_WITH_SEED_CBC_SHA                 | DHE-DSS-SEED-SHA                   | [RFC4162]          |
| 0x009A | TLS_DHE_RSA_WITH_SEED_CBC_SHA                 | DHE-RSA-SEED-SHA                   | [RFC4162]          |
| 0x009B | TLS_DH_anon_WITH_SEED_CBC_SHA                 | ADH-SEED-SHA                       | [RFC4162]          |
| 0x009C | TLS_RSA_WITH_AES_128_GCM_SHA256               | AES128-GCM-SHA256                  | [RFC5288]          |
| 0x009D | TLS_RSA_WITH_AES_256_GCM_SHA384               | AES256-GCM-SHA384                  | [RFC5288]          |
| 0x009E | TLS_DHE_RSA_WITH_AES_128_GCM_SHA256           | DHE-RSA-AES128-GCM-SHA256          | [RFC5288]          |
| 0x009F | TLS_DHE_RSA_WITH_AES_256_GCM_SHA384           | DHE-RSA-AES256-GCM-SHA384          | [RFC5288]          |
| 0x00A0 | TLS_DH_RSA_WITH_AES_128_GCM_SHA256            | DH-RSA-AES128-GCM-SHA256           | [RFC5288]          |
| 0x00A1 | TLS_DH_RSA_WITH_AES_256_GCM_SHA384            | DH-RSA-AES256-GCM-SHA384           | [RFC5288]          |
| 0x00A2 | TLS_DHE_DSS_WITH_AES_128_GCM_SHA256           | DHE-DSS-AES128-GCM-SHA256          | [RFC5288]          |
| 0x00A3 | TLS_DHE_DSS_WITH_AES_256_GCM_SHA384           | DHE-DSS-AES256-GCM-SHA384          | [RFC5288]          |
| 0x00A4 | TLS_DH_DSS_WITH_AES_128_GCM_SHA256            | DH-DSS-AES128-GCM-SHA256           | [RFC5288]          |
| 0x00A5 | TLS_DH_DSS_WITH_AES_256_GCM_SHA384            | DH-DSS-AES256-GCM-SHA384           | [RFC5288]          |
| 0x00A6 | TLS_DH_anon_WITH_AES_128_GCM_SHA256           | ADH-AES128-GCM-SHA256              | [RFC5288]          |
| 0x00A7 | TLS_DH_anon_WITH_AES_256_GCM_SHA384           | ADH-AES256-GCM-SHA384              | [RFC5288]          |
| 0x00A8 | TLS_PSK_WITH_AES_128_GCM_SHA256               | PSK-AES128-GCM-SHA256              | [RFC5487]          |
| 0x00A9 | TLS_PSK_WITH_AES_256_GCM_SHA384               | PSK-AES256-GCM-SHA384              | [RFC5487]          |
| 0x00AA | TLS_DHE_PSK_WITH_AES_128_GCM_SHA256           | DHE-PSK-AES128-GCM-SHA256          | [RFC5487]          |
| 0x00AB | TLS_DHE_PSK_WITH_AES_256_GCM_SHA384           | DHE-PSK-AES256-GCM-SHA384          | [RFC5487]          |
| 0x00AC | TLS_RSA_PSK_WITH_AES_128_GCM_SHA256           | RSA-PSK-AES128-GCM-SHA256          | [RFC5487]          |
| 0x00AD | TLS_RSA_PSK_WITH_AES_256_GCM_SHA384           | RSA-PSK-AES256-GCM-SHA384          | [RFC5487]          |
| 0x00AE | TLS_PSK_WITH_AES_128_CBC_SHA256               | PSK-AES128-CBC-SHA256              | [RFC5487]          |
| 0x00AF | TLS_PSK_WITH_AES_256_CBC_SHA384               | PSK-AES256-CBC-SHA384              | [RFC5487]          |
| 0x00B0 | TLS_PSK_WITH_NULL_SHA256                      | PSK-NULL-SHA256                    | [RFC5487]          |
| 0x00B1 | TLS_PSK_WITH_NULL_SHA384                      | PSK-NULL-SHA384                    | [RFC5487]          |
| 0x00B2 | TLS_DHE_PSK_WITH_AES_128_CBC_SHA256           | DHE-PSK-AES128-CBC-SHA256          | [RFC5487]          |
| 0x00B3 | TLS_DHE_PSK_WITH_AES_256_CBC_SHA384           | DHE-PSK-AES256-CBC-SHA384          | [RFC5487]          |
| 0x00B4 | TLS_DHE_PSK_WITH_NULL_SHA256                  | DHE-PSK-NULL-SHA256                | [RFC5487]          |
| 0x00B5 | TLS_DHE_PSK_WITH_NULL_SHA384                  | DHE-PSK-NULL-SHA384                | [RFC5487]          |
| 0x00B6 | TLS_RSA_PSK_WITH_AES_128_CBC_SHA256           | RSA-PSK-AES128-CBC-SHA256          | [RFC5487]          |
| 0x00B7 | TLS_RSA_PSK_WITH_AES_256_CBC_SHA384           | RSA-PSK-AES256-CBC-SHA384          | [RFC5487]          |
| 0x00B8 | TLS_RSA_PSK_WITH_NULL_SHA256                  | RSA-PSK-NULL-SHA256                | [RFC5487]          |
| 0x00B9 | TLS_RSA_PSK_WITH_NULL_SHA384                  | RSA-PSK-NULL-SHA384                | [RFC5487]          |
| 0x00BA | TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256          | CAMELLIA128-SHA256                 | [RFC5932]          |
| 0x00BD | TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256      | DHE-DSS-CAMELLIA128-SHA256         | [RFC5932]          |
| 0x00BE | TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256      | DHE-RSA-CAMELLIA128-SHA256         | [RFC5932]          |
| 0x00BF | TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256      | ADH-CAMELLIA128-SHA256             | [RFC5932]          |
| 0x00C0 | TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256          | CAMELLIA256-SHA256                 | [RFC5932]          |
| 0x00C3 | TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256      | DHE-DSS-CAMELLIA256-SHA256         | [RFC5932]          |
| 0x00C4 | TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256      | DHE-RSA-CAMELLIA256-SHA256         | [RFC5932]          |
| 0x00C5 | TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256      | ADH-CAMELLIA256-SHA256             | [RFC5932]          |
| 0x00FF | TLS_EMPTY_RENEGOTIATION_INFO_SCSV             |                                    | [RFC5746]          |
| 0x5600 | TLS_FALLBACK_SCSV                             |                                    | [RFC7507]          |
| 0xC001 | TLS_ECDH_ECDSA_WITH_NULL_SHA                  | ECDH-ECDSA-NULL-SHA                | [RFC8422]          |
| 0xC002 | TLS_ECDH_ECDSA_WITH_RC4_128_SHA               | ECDH-ECDSA-RC4-SHA                 | [RFC8422][RFC6347] |
| 0xC003 | TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA          | ECDH-ECDSA-DES-CBC3-SHA            | [RFC8422]          |
| 0xC004 | TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA           | ECDH-ECDSA-AES128-SHA              | [RFC8422]          |
| 0xC005 | TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA           | ECDH-ECDSA-AES256-SHA              | [RFC8422]          |
| 0xC006 | TLS_ECDHE_ECDSA_WITH_NULL_SHA                 | ECDHE-ECDSA-NULL-SHA               | [RFC8422]          |
| 0xC007 | TLS_ECDHE_ECDSA_WITH_RC4_128_SHA              | ECDHE-ECDSA-RC4-SHA                | [RFC8422][RFC6347] |
| 0xC008 | TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA         | ECDHE-ECDSA-DES-CBC3-SHA           | [RFC8422]          |
| 0xC009 | TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA          | ECDHE-ECDSA-AES128-SHA             | [RFC8422]          |
| 0xC00A | TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA          | ECDHE-ECDSA-AES256-SHA             | [RFC8422]          |
| 0xC00B | TLS_ECDH_RSA_WITH_NULL_SHA                    | ECDH-RSA-NULL-SHA                  | [RFC8422]          |
| 0xC00C | TLS_ECDH_RSA_WITH_RC4_128_SHA                 | ECDH-RSA-RC4-SHA                   | [RFC8422][RFC6347] |
| 0xC00D | TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA            | ECDH-RSA-DES-CBC3-SHA              | [RFC8422]          |
| 0xC00E | TLS_ECDH_RSA_WITH_AES_128_CBC_SHA             | ECDH-RSA-AES128-SHA                | [RFC8422]          |
| 0xC00F | TLS_ECDH_RSA_WITH_AES_256_CBC_SHA             | ECDH-RSA-AES256-SHA                | [RFC8422]          |
| 0xC010 | TLS_ECDHE_RSA_WITH_NULL_SHA                   | ECDHE-RSA-NULL-SHA                 | [RFC8422]          |
| 0xC011 | TLS_ECDHE_RSA_WITH_RC4_128_SHA                | ECDHE-RSA-RC4-SHA                  | [RFC8422][RFC6347] |
| 0xC012 | TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA           | ECDHE-RSA-DES-CBC3-SHA             | [RFC8422]          |
| 0xC013 | TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA            | ECDHE-RSA-AES128-SHA               | [RFC8422]          |
| 0xC014 | TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA            | ECDHE-RSA-AES256-SHA               | [RFC8422]          |
| 0xC015 | TLS_ECDH_anon_WITH_NULL_SHA                   | AECDH-NULL-SHA                     | [RFC8422]          |
| 0xC016 | TLS_ECDH_anon_WITH_RC4_128_SHA                | AECDH-RC4-SHA                      | [RFC8422][RFC6347] |
| 0xC017 | TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA           | AECDH-DES-CBC3-SHA                 | [RFC8422]          |
| 0xC018 | TLS_ECDH_anon_WITH_AES_128_CBC_SHA            | AECDH-AES128-SHA                   | [RFC8422]          |
| 0xC019 | TLS_ECDH_anon_WITH_AES_256_CBC_SHA            | AECDH-AES256-SHA                   | [RFC8422]          |
| 0xC01A | TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA             | SRP-3DES-EDE-CBC-SHA               | [RFC5054]          |
| 0xC01B | TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA         | SRP-RSA-3DES-EDE-CBC-SHA           | [RFC5054]          |
| 0xC01C | TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA         | SRP-DSS-3DES-EDE-CBC-SHA           | [RFC5054]          |
| 0xC01D | TLS_SRP_SHA_WITH_AES_128_CBC_SHA              | SRP-AES-128-CBC-SHA                | [RFC5054]          |
| 0xC01E | TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA          | SRP-RSA-AES-128-CBC-SHA            | [RFC5054]          |
| 0xC01F | TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA          | SRP-DSS-AES-128-CBC-SHA            | [RFC5054]          |
| 0xC020 | TLS_SRP_SHA_WITH_AES_256_CBC_SHA              | SRP-AES-256-CBC-SHA                | [RFC5054]          |
| 0xC021 | TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA          | SRP-RSA-AES-256-CBC-SHA            | [RFC5054]          |
| 0xC022 | TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA          | SRP-DSS-AES-256-CBC-SHA            | [RFC5054]          |
| 0xC023 | TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256       | ECDHE-ECDSA-AES128-SHA256          | [RFC5289]          |
| 0xC024 | TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384       | ECDHE-ECDSA-AES256-SHA384          | [RFC5289]          |
| 0xC025 | TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256        | ECDH-ECDSA-AES128-SHA256           | [RFC5289]          |
| 0xC026 | TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384        | ECDH-ECDSA-AES256-SHA384           | [RFC5289]          |
| 0xC027 | TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256         | ECDHE-RSA-AES128-SHA256            | [RFC5289]          |
| 0xC028 | TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384         | ECDHE-RSA-AES256-SHA384            | [RFC5289]          |
| 0xC029 | TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256          | ECDH-RSA-AES128-SHA256             | [RFC5289]          |
| 0xC02A | TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384          | ECDH-RSA-AES256-SHA384             | [RFC5289]          |
| 0xC02B | TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256       | ECDHE-ECDSA-AES128-GCM-SHA256      | [RFC5289]          |
| 0xC02C | TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384       | ECDHE-ECDSA-AES256-GCM-SHA384      | [RFC5289]          |
| 0xC02D | TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256        | ECDH-ECDSA-AES128-GCM-SHA256       | [RFC5289]          |
| 0xC02E | TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384        | ECDH-ECDSA-AES256-GCM-SHA384       | [RFC5289]          |
| 0xC02F | TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256         | ECDHE-RSA-AES128-GCM-SHA256        | [RFC5289]          |
| 0xC030 | TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384         | ECDHE-RSA-AES256-GCM-SHA384        | [RFC5289]          |
| 0xC031 | TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256          | ECDH-RSA-AES128-GCM-SHA256         | [RFC5289]          |
| 0xC032 | TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384          | ECDH-RSA-AES256-GCM-SHA384         | [RFC5289]          |
| 0xC033 | TLS_ECDHE_PSK_WITH_RC4_128_SHA                | ECDHE-PSK-RC4-SHA                  | [RFC5489][RFC6347] |
| 0xC034 | TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA           | ECDHE-PSK-3DES-EDE-CBC-SHA         | [RFC5489]          |
| 0xC035 | TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA            | ECDHE-PSK-AES128-CBC-SHA           | [RFC5489]          |
| 0xC036 | TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA            | ECDHE-PSK-AES256-CBC-SHA           | [RFC5489]          |
| 0xC037 | TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256         | ECDHE-PSK-AES128-CBC-SHA256        | [RFC5489]          |
| 0xC038 | TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384         | ECDHE-PSK-AES256-CBC-SHA384        | [RFC5489]          |
| 0xC039 | TLS_ECDHE_PSK_WITH_NULL_SHA                   | ECDHE-PSK-NULL-SHA                 | [RFC5489]          |
| 0xC03A | TLS_ECDHE_PSK_WITH_NULL_SHA256                | ECDHE-PSK-NULL-SHA256              | [RFC5489]          |
| 0xC03B | TLS_ECDHE_PSK_WITH_NULL_SHA384                | ECDHE-PSK-NULL-SHA384              | [RFC5489]          |
| 0xC03C | TLS_RSA_WITH_ARIA_128_CBC_SHA256              | ARIA128-SHA256                     | [RFC6209]          |
| 0xC03D | TLS_RSA_WITH_ARIA_256_CBC_SHA384              | ARIA256-SHA384                     | [RFC6209]          |
| 0xC044 | TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256          | DHE-RSA-ARIA128-SHA256             | [RFC6209]          |
| 0xC045 | TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384          | DHE-RSA-ARIA256-SHA384             | [RFC6209]          |
| 0xC048 | TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256      | ECDHE-ECDSA-ARIA128-SHA256         | [RFC6209]          |
| 0xC049 | TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384      | ECDHE-ECDSA-ARIA256-SHA384         | [RFC6209]          |
| 0xC04A | TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256       | ECDH-ECDSA-ARIA128-SHA256          | [RFC6209]          |
| 0xC04B | TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384       | ECDH-ECDSA-ARIA256-SHA384          | [RFC6209]          |
| 0xC04C | TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256        | ECDHE-ARIA128-SHA256               | [RFC6209]          |
| 0xC04D | TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384        | ECDHE-ARIA256-SHA384               | [RFC6209]          |
| 0xC04E | TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256         | ECDH-ARIA128-SHA256                | [RFC6209]          |
| 0xC04F | TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384         | ECDH-ARIA256-SHA384                | [RFC6209]          |
| 0xC050 | TLS_RSA_WITH_ARIA_128_GCM_SHA256              | ARIA128-GCM-SHA256                 | [RFC6209]          |
| 0xC051 | TLS_RSA_WITH_ARIA_256_GCM_SHA384              | ARIA256-GCM-SHA384                 | [RFC6209]          |
| 0xC052 | TLS_DHE_RSA_WITH_ARIA_128_GCM_SHA256          | DHE-RSA-ARIA128-GCM-SHA256         | [RFC6209]          |
| 0xC053 | TLS_DHE_RSA_WITH_ARIA_256_GCM_SHA384          | DHE-RSA-ARIA256-GCM-SHA384         | [RFC6209]          |
| 0xC056 | TLS_DHE_DSS_WITH_ARIA_128_GCM_SHA256          | DHE-DSS-ARIA128-GCM-SHA256         | [RFC6209]          |
| 0xC057 | TLS_DHE_DSS_WITH_ARIA_256_GCM_SHA384          | DHE-DSS-ARIA256-GCM-SHA384         | [RFC6209]          |
| 0xC05C | TLS_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256      | ECDHE-ECDSA-ARIA128-GCM-SHA256     | [RFC6209]          |
| 0xC05D | TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384      | ECDHE-ECDSA-ARIA256-GCM-SHA384     | [RFC6209]          |
| 0xC05E | TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256       | ECDH-ECDSA-ARIA128-GCM-SHA256      | [RFC6209]          |
| 0xC05F | TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384       | ECDH-ECDSA-ARIA256-GCM-SHA384      | [RFC6209]          |
| 0xC060 | TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256        | ECDHE-ARIA128-GCM-SHA256           | [RFC6209]          |
| 0xC061 | TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384        | ECDHE-ARIA256-GCM-SHA384           | [RFC6209]          |
| 0xC062 | TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256         | ECDH-ARIA128-GCM-SHA256            | [RFC6209]          |
| 0xC063 | TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384         | ECDH-ARIA256-GCM-SHA384            | [RFC6209]          |
| 0xC064 | TLS_PSK_WITH_ARIA_128_CBC_SHA256              | PSK-ARIA128-SHA256                 | [RFC6209]          |
| 0xC065 | TLS_PSK_WITH_ARIA_256_CBC_SHA384              | PSK-ARIA256-SHA384                 | [RFC6209]          |
| 0xC066 | TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256          | DHE-PSK-ARIA128-SHA256             | [RFC6209]          |
| 0xC067 | TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384          | DHE-PSK-ARIA256-SHA384             | [RFC6209]          |
| 0xC068 | TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256          | RSA-PSK-ARIA128-SHA256             | [RFC6209]          |
| 0xC069 | TLS_RSA_PSK_WITH_ARIA_256_CBC_SHA384          | RSA-PSK-ARIA256-SHA384             | [RFC6209]          |
| 0xC06A | TLS_PSK_WITH_ARIA_128_GCM_SHA256              | PSK-ARIA128-GCM-SHA256             | [RFC6209]          |
| 0xC06B | TLS_PSK_WITH_ARIA_256_GCM_SHA384              | PSK-ARIA256-GCM-SHA384             | [RFC6209]          |
| 0xC06C | TLS_DHE_PSK_WITH_ARIA_128_GCM_SHA256          | DHE-PSK-ARIA128-GCM-SHA256         | [RFC6209]          |
| 0xC06D | TLS_DHE_PSK_WITH_ARIA_256_GCM_SHA384          | DHE-PSK-ARIA256-GCM-SHA384         | [RFC6209]          |
| 0xC06E | TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256          | RSA-PSK-ARIA128-GCM-SHA256         | [RFC6209]          |
| 0xC06F | TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384          | RSA-PSK-ARIA256-GCM-SHA384         | [RFC6209]          |
| 0xC070 | TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256        | ECDHE-PSK-ARIA128-SHA256           | [RFC6209]          |
| 0xC071 | TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384        | ECDHE-PSK-ARIA256-SHA384           | [RFC6209]          |
| 0xC072 | TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256  | ECDHE-ECDSA-CAMELLIA128-SHA256     | [RFC6367]          |
| 0xC073 | TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384  | ECDHE-ECDSA-CAMELLIA256-SHA384     | [RFC6367]          |
| 0xC074 | TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256   | ECDH-ECDSA-CAMELLIA128-SHA256      | [RFC6367]          |
| 0xC075 | TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384   | ECDH-ECDSA-CAMELLIA256-SHA384      | [RFC6367]          |
| 0xC076 | TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256    | ECDHE-RSA-CAMELLIA128-SHA256       | [RFC6367]          |
| 0xC077 | TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384    | ECDHE-RSA-CAMELLIA256-SHA384       | [RFC6367]          |
| 0xC078 | TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256     | ECDH-CAMELLIA128-SHA256            | [RFC6367]          |
| 0xC079 | TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384     | ECDH-CAMELLIA256-SHA384            | [RFC6367]          |
| 0xC07A | TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256          | CAMELLIA128-GCM-SHA256             | [RFC6367]          |
| 0xC07B | TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384          | CAMELLIA256-GCM-SHA384             | [RFC6367]          |
| 0xC07C | TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256      | DHE-RSA-CAMELLIA128-GCM-SHA256     | [RFC6367]          |
| 0xC07D | TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384      | DHE-RSA-CAMELLIA256-GCM-SHA384     | [RFC6367]          |
| 0xC086 | TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256  | ECDHE-ECDSA-CAMELLIA128-GCM-SHA256 | [RFC6367]          |
| 0xC087 | TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384  | ECDHE-ECDSA-CAMELLIA256-GCM-SHA384 | [RFC6367]          |
| 0xC088 | TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256   | ECDH-ECDSA-CAMELLIA128-GCM-SHA256  | [RFC6367]          |
| 0xC089 | TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384   | ECDH-ECDSA-CAMELLIA256-GCM-SHA384  | [RFC6367]          |
| 0xC08A | TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256    | ECDHE-CAMELLIA128-GCM-SHA256       | [RFC6367]          |
| 0xC08B | TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384    | ECDHE-CAMELLIA256-GCM-SHA384       | [RFC6367]          |
| 0xC08C | TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256     | ECDH-CAMELLIA128-GCM-SHA256        | [RFC6367]          |
| 0xC08D | TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384     | ECDH-CAMELLIA256-GCM-SHA384        | [RFC6367]          |
| 0xC08E | TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256          | PSK-CAMELLIA128-GCM-SHA256         | [RFC6367]          |
| 0xC08F | TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384          | PSK-CAMELLIA256-GCM-SHA384         | [RFC6367]          |
| 0xC090 | TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256      | DHE-PSK-CAMELLIA128-GCM-SHA256     | [RFC6367]          |
| 0xC091 | TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384      | DHE-PSK-CAMELLIA256-GCM-SHA384     | [RFC6367]          |
| 0xC092 | TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256      | RSA-PSK-CAMELLIA128-GCM-SHA256     | [RFC6367]          |
| 0xC093 | TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384      | RSA-PSK-CAMELLIA256-GCM-SHA384     | [RFC6367]          |
| 0xC094 | TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256          | PSK-CAMELLIA128-SHA256             | [RFC6367]          |
| 0xC095 | TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384          | PSK-CAMELLIA256-SHA384             | [RFC6367]          |
| 0xC096 | TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256      | DHE-PSK-CAMELLIA128-SHA256         | [RFC6367]          |
| 0xC097 | TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384      | DHE-PSK-CAMELLIA256-SHA384         | [RFC6367]          |
| 0xC098 | TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256      | RSA-PSK-CAMELLIA128-SHA256         | [RFC6367]          |
| 0xC099 | TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384      | RSA-PSK-CAMELLIA256-SHA384         | [RFC6367]          |
| 0xC09A | TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256    | ECDHE-PSK-CAMELLIA128-SHA256       | [RFC6367]          |
| 0xC09B | TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384    | ECDHE-PSK-CAMELLIA256-SHA384       | [RFC6367]          |
| 0xC09C | TLS_RSA_WITH_AES_128_CCM                      | AES128-CCM                         | [RFC6655]          |
| 0xC09D | TLS_RSA_WITH_AES_256_CCM                      | AES256-CCM                         | [RFC6655]          |
| 0xC09E | TLS_DHE_RSA_WITH_AES_128_CCM                  | DHE-RSA-AES128-CCM                 | [RFC6655]          |
| 0xC09F | TLS_DHE_RSA_WITH_AES_256_CCM                  | DHE-RSA-AES256-CCM                 | [RFC6655]          |
| 0xC0A0 | TLS_RSA_WITH_AES_128_CCM_8                    | AES128-CCM8                        | [RFC6655]          |
| 0xC0A1 | TLS_RSA_WITH_AES_256_CCM_8                    | AES256-CCM8                        | [RFC6655]          |
| 0xC0A2 | TLS_DHE_RSA_WITH_AES_128_CCM_8                | DHE-RSA-AES128-CCM8                | [RFC6655]          |
| 0xC0A3 | TLS_DHE_RSA_WITH_AES_256_CCM_8                | DHE-RSA-AES256-CCM8                | [RFC6655]          |
| 0xC0A4 | TLS_PSK_WITH_AES_128_CCM                      | PSK-AES128-CCM                     | [RFC6655]          |
| 0xC0A5 | TLS_PSK_WITH_AES_256_CCM                      | PSK-AES256-CCM                     | [RFC6655]          |
| 0xC0A6 | TLS_DHE_PSK_WITH_AES_128_CCM                  | DHE-PSK-AES128-CCM                 | [RFC6655]          |
| 0xC0A7 | TLS_DHE_PSK_WITH_AES_256_CCM                  | DHE-PSK-AES256-CCM                 | [RFC6655]          |
| 0xC0A8 | TLS_PSK_WITH_AES_128_CCM_8                    | PSK-AES128-CCM8                    | [RFC6655]          |
| 0xC0A9 | TLS_PSK_WITH_AES_256_CCM_8                    | PSK-AES256-CCM8                    | [RFC6655]          |
| 0xC0AA | TLS_PSK_DHE_WITH_AES_128_CCM_8                | DHE-PSK-AES128-CCM8                | [RFC6655]          |
| 0xC0AB | TLS_PSK_DHE_WITH_AES_256_CCM_8                | DHE-PSK-AES256-CCM8                | [RFC6655]          |
| 0xC0AC | TLS_ECDHE_ECDSA_WITH_AES_128_CCM              | ECDHE-ECDSA-AES128-CCM             | [RFC7251]          |
| 0xC0AD | TLS_ECDHE_ECDSA_WITH_AES_256_CCM              | ECDHE-ECDSA-AES256-CCM             | [RFC7251]          |
| 0xC0AE | TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8            | ECDHE-ECDSA-AES128-CCM8            | [RFC7251]          |
| 0xC0AF | TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8            | ECDHE-ECDSA-AES256-CCM8            | [RFC7251]          |
| 0xC100 | TLS_GOSTR341112_256_WITH_KUZNYECHIK_CTR_OMAC  | GOST2012-KUZNYECHIK-KUZNYECHIKOMAC | [RFC9189]          |
| 0xC101 | TLS_GOSTR341112_256_WITH_MAGMA_CTR_OMAC       | GOST2012-MAGMA-MAGMAOMAC           | [RFC9189]          |
| 0xC102 | TLS_GOSTR341112_256_WITH_28147_CNT_IMIT       | IANA-GOST2012-GOST8912-GOST8912    | [RFC9189]          |
| 0xCC13 |                                               | ECDHE-RSA-CHACHA20-POLY1305-OLD    |                    |
| 0xCC14 |                                               | ECDHE-ECDSA-CHACHA20-POLY1305-OLD  |                    |
| 0xCC15 |                                               | DHE-RSA-CHACHA20-POLY1305-OLD      |                    |
| 0xCCA8 | TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256   | ECDHE-RSA-CHACHA20-POLY1305        | [RFC7905]          |
| 0xCCA9 | TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 | ECDHE-ECDSA-CHACHA20-POLY1305      | [RFC7905]          |
| 0xCCAA | TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256     | DHE-RSA-CHACHA20-POLY1305          | [RFC7905]          |
| 0xCCAB | TLS_PSK_WITH_CHACHA20_POLY1305_SHA256         | PSK-CHACHA20-POLY1305              | [RFC7905]          |
| 0xCCAC | TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256   | ECDHE-PSK-CHACHA20-POLY1305        | [RFC7905]          |
| 0xCCAD | TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256     | DHE-PSK-CHACHA20-POLY1305          | [RFC7905]          |
| 0xCCAE | TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256     | RSA-PSK-CHACHA20-POLY1305          | [RFC7905]          |
| 0xD001 | TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256         | ECDHE-PSK-AES128-GCM-SHA256        | [RFC8442]          |
| 0xE011 |                                               | ECDHE-ECDSA-SM4-CBC-SM3            |                    |
| 0xE051 |                                               | ECDHE-ECDSA-SM4-GCM-SM3            |                    |
| 0xE052 |                                               | ECDHE-ECDSA-SM4-CCM-SM3            |                    |
| 0xFF00 |                                               | GOST-MD5                           |                    |
| 0xFF01 |                                               | GOST-GOST94                        |                    |
| 0xFF02 |                                               | GOST-GOST89MAC                     |                    |
| 0xFF03 |                                               | GOST-GOST89STREAM                  |                    |
<!--
Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.

SPDX-License-Identifier: curl
-->

# Contributor Code of Conduct

As contributors and maintainers of this project, we pledge to respect all
people who contribute through reporting issues, posting feature requests,
updating documentation, submitting pull requests or patches, and other
activities.

We are committed to making participation in this project a harassment-free
experience for everyone, regardless of level of experience, gender, gender
identity and expression, sexual orientation, disability, personal appearance,
body size, race, ethnicity, age, or religion.

Examples of unacceptable behavior by participants include the use of sexual
language or imagery, derogatory comments or personal attacks, trolling, public
or private harassment, insults, or other unprofessional conduct.

Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct. Project maintainers who do not
follow the Code of Conduct may be removed from the project team.

This code of conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community.

Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by opening an issue or contacting one or more of the project
maintainers.

This Code of Conduct is adapted from the
[Contributor Covenant](https://contributor-covenant.org/), version 1.1.0,
available at
[https://contributor-covenant.org/version/1/1/0/](https://contributor-covenant.org/version/1/1/0/)
<!--
Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.

SPDX-License-Identifier: curl
-->

# How to do code reviews for curl

Anyone and everyone is encouraged and welcome to review code submissions in
curl. This is a guide on what to check for and how to perform a successful
code review.

## All submissions should get reviewed

All pull requests and patches submitted to the project should be reviewed by
at least one experienced curl maintainer before that code is accepted and
merged.

## Let the tools and tests take the first rounds

On initial pull requests, let the tools and tests do their job first and then
start out by helping the submitter understand the test failures and tool
alerts.

## How to provide feedback to author

Be nice. Ask questions. Provide examples or suggestions of improvements.
Assume the best intentions. Remember language barriers.

All first-time contributors can become regulars. Let's help them go there.

## Is this a change we want?

If this is not a change that seems to be aligned with the project's path
forward and as such cannot be accepted, inform the author about this sooner
rather than later. Do it gently and explain why and possibly what could be
done to make it more acceptable.

## API/ABI stability or changed behavior

Changing the API and the ABI may be fine in a change but it needs to be done
deliberately and carefully. If not, a reviewer must help the author to realize
the mistake.

curl and libcurl are similarly strict on not modifying existing behavior. API
and ABI stability is not enough, the behavior should also remain intact as far
as possible.

## Code style

Most code style nits are detected by checksrc but not all. Only leave remarks
on style deviation once checksrc does not find anymore.

Minor nits from fresh submitters can also be handled by the maintainer when
merging, in case it seems like the submitter is not clear on what to do. We
want to make the process fun and exciting for new contributors.

## Encourage consistency

Make sure new code is written in a similar style as existing code. Naming,
logic, conditions, etc.

## Are pointers always non-NULL?

If a function or code rely on pointers being non-NULL, take an extra look if
that seems to be a fair assessment.

## Asserts

Conditions that should never be false can be verified with `DEBUGASSERT()`
calls to get caught in tests and debugging easier, while not having an impact
on final or release builds.

## Memory allocation

Can the mallocs be avoided? Do not introduce mallocs in any hot paths. If
there are (new) mallocs, can they be combined into fewer calls?

Are all allocations handled in error paths to avoid leaks and crashes?

## Thread-safety

We do not like static variables as they break thread-safety and prevent
functions from being reentrant.

## Should features be `#ifdef`ed?

Features and functionality may not be present everywhere and should therefore
be `#ifdef`ed. Additionally, some features should be possible to switch on/off
in the build.

Write `#ifdef`s to be as little of a "maze" as possible.

## Does it look portable enough?

curl runs "everywhere". Does the code take a reasonable stance and enough
precautions to be possible to build and run on most platforms?

Remember that we live by C89 restrictions.

## Tests and testability

New features should be added in conjunction with one or more test cases.
Ideally, functions should also be written so that unit tests can be done to
test individual functions.

## Documentation

New features or changes to existing functionality **must** be accompanied by
updated documentation. Submitting that in a separate follow-up pull request is
not OK. A code review must also verify that the submitted documentation update
matches the code submission.

English is not everyone's first language, be mindful of this and help the
submitter improve the text if it needs a rewrite to read better.

## Code should not be hard to understand

Source code should be written to maximize readability and be easy to
understand.

## Functions should not be large

A single function should never be large as that makes it hard to follow and
understand all the exit points and state changes. Some existing functions in
curl certainly violate this ground rule but when reviewing new code we should
propose splitting into smaller functions.

## Duplication is evil

Anything that looks like duplicated code is a red flag. Anything that seems to
introduce code that we *should* already have or provide needs a closer check.

## Sensitive data

When credentials are involved, take an extra look at what happens with this
data. Where it comes from and where it goes.

## Variable types differ

`size_t` is not a fixed size. `time_t` can be signed or unsigned and have
different sizes. Relying on variable sizes is a red flag.

Also remember that endianness and >= 32-bit accesses to unaligned addresses
are problematic areas.

## Integer overflows

Be careful about integer overflows. Some variable types can be either 32-bit
or 64-bit. Integer overflows must be detected and acted on *before* they
happen.

## Dangerous use of functions

Maybe use of `realloc()` should rather use the dynbuf functions?

Do not allow new code that grows buffers without using dynbuf.

Use of C functions that rely on a null-terminator must only be used on data
that really do have a null-terminator (`\0` byte).

## Dangerous "data styles"

Make extra precautions and verify that memory buffers that need
null-terminator always have exactly that. Buffers *without* a null-terminator
must not be used as input to string functions.

# Commit messages

Tightly coupled with a code review is making sure that the commit message is
good. It is the responsibility of the person who merges the code to make sure
that the commit message follows our standard (detailed in the
[CONTRIBUTE](https://curl.se/dev/contribute.html) document). This includes
making sure the PR identifies related issues and giving credit to reporters
and helpers.
<!--
Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.

SPDX-License-Identifier: curl
-->

# Contributing to the curl project

This document is intended to offer guidelines on how to best contribute to the
curl project. This concerns new features as well as corrections to existing
flaws or bugs.

## Join the Community

Skip over to [https://curl.se/mail/](https://curl.se/mail/) and join
the appropriate mailing list(s). Read up on details before you post
questions. Read this file before you start sending patches. We prefer
questions sent to and discussions being held on the mailing list(s), not sent
to individuals.

Before posting to one of the curl mailing lists, please read up on the
[mailing list etiquette](https://curl.se/mail/etiquette.html).

We also hang out on IRC in #curl on libera.chat

If you are at all interested in the code side of things, consider clicking
'watch' on the [curl repository on GitHub](https://github.com/curl/curl) to be
notified of pull requests and new issues posted there.

## License and copyright

When contributing with code, you agree to put your changes and new code under
the same license curl and libcurl is already using unless stated and agreed
otherwise.

If you add a larger piece of code, you can opt to make that file or set of
files to use a different license as long as they do not enforce any changes to
the rest of the package and they make sense. Such "separate parts" can not be
GPL licensed (as we do not want copyleft to affect users of libcurl) but they
must use "GPL compatible" licenses (as we want to allow users to use libcurl
properly in GPL licensed environments).

When changing existing source code, you do not alter the copyright of the
original file(s). The copyright is still owned by the original creator(s) or
those who have been assigned copyright by the original author(s).

By submitting a patch to the curl project, you are assumed to have the right
to the code and to be allowed by your employer or whatever to hand over that
patch/code to us. We credit you for your changes as far as possible, to give
credit but also to keep a trace back to who made what changes. Please always
provide us with your full real name when contributing.

## What To Read

Source code, the man pages, the [INTERNALS
document](https://curl.se/dev/internals.html),
[TODO](https://curl.se/docs/todo.html),
[KNOWN_BUGS](https://curl.se/docs/knownbugs.html) and the [most recent
changes](https://curl.se/dev/sourceactivity.html) in git. Lurking on the
[curl-library mailing list](https://curl.se/mail/list.cgi?list=curl-library)
gives you a lot of insights on what's going on right now. Asking there is a
good idea too.

## Write a good patch

### Follow code style

When writing C code, follow the
[CODE_STYLE](https://curl.se/dev/code-style.html) already established in
the project. Consistent style makes code easier to read and mistakes less
likely to happen. Run `make checksrc` before you submit anything, to make sure
you follow the basic style. That script does not verify everything, but if it
complains you know you have work to do.

### Non-clobbering All Over

When you write new functionality or fix bugs, it is important that you do not
fiddle all over the source files and functions. Remember that it is likely
that other people have done changes in the same source files as you have and
possibly even in the same functions. If you bring completely new
functionality, try writing it in a new source file. If you fix bugs, try to
fix one bug at a time and send them as separate patches.

### Write Separate Changes

It is annoying when you get a huge patch from someone that is said to fix 11
odd problems, but discussions and opinions do not agree with 10 of them - or 9
of them were already fixed in a different way. Then the person merging this
change needs to extract the single interesting patch from somewhere within the
huge pile of source, and that creates a lot of extra work.

Preferably, each fix that corrects a problem should be in its own patch/commit
with its own description/commit message stating exactly what they correct so
that all changes can be selectively applied by the maintainer or other
interested parties.

Also, separate changes enable bisecting much better for tracking problems
and regression in the future.

### Patch Against Recent Sources

Please try to get the latest available sources to make your patches against.
It makes the lives of the developers so much easier. The best is if you get
the most up-to-date sources from the git repository, but the latest release
archive is OK as well.

### Documentation

Writing docs is dead boring and one of the big problems with many open source
projects but someone's gotta do it. It makes things a lot easier if you submit
a small description of your fix or your new features with every contribution
so that it can be swiftly added to the package documentation.

Documentation is mostly provided as man pages or plain ASCII files. The
man pages are rendered from their source files that are usually written using
markdown. Most HTML files on the website and in the release archives are
generated from corresponding markdown and ASCII files.

### Test Cases

Since the introduction of the test suite, we can quickly verify that the main
features are working as they are supposed to. To maintain this situation and
improve it, all new features and functions that are added need to be tested in
the test suite. Every feature that is added should get at least one valid test
case that verifies that it works as documented. If every submitter also posts
a few test cases, it does not end up a heavy burden on a single person.

If you do not have test cases or perhaps you have done something that is hard
to write tests for, do explain exactly how you have otherwise tested and
verified your changes.

# Submit Your Changes

## Get your changes merged

Ideally you file a [pull request on
GitHub](https://github.com/curl/curl/pulls), but you can also send your plain
patch to [the curl-library mailing
list](https://curl.se/mail/list.cgi?list=curl-library).

If you opt to post a patch on the mailing list, chances are someone converts
it into a pull request for you, to have the CI jobs verify it proper before it
can be merged. Be prepared that some feedback on the proposed change might
then come on GitHub.

As your changes are reviewed and discussed, you are expected to address any
flaws pointed out and update accordingly. Otherwise your changes risk stalling
and eventually being deleted without action. As a submitter of a change, you
are the owner of that change until it has been merged.

Respond on the list or on GitHub about the change and answer questions and/or
fix nits/flaws. This is important. We take lack of replies as a sign that you
are not anxious to get your patch accepted and we tend to drop such
changes.

## About pull requests

With GitHub it is easy to send a [pull
request](https://github.com/curl/curl/pulls) to the curl project to have
changes merged.

We strongly prefer pull requests to mailed patches, as it makes it a proper
git commit that is easy to merge and they are easy to track and not that easy
to lose in the flood of many emails, like they sometimes do on the mailing
lists.

Every pull request submitted is automatically tested in several different
ways. [See the CI document for more
information](https://github.com/curl/curl/blob/master/docs/tests/CI.md).

Sometimes the tests fail due to a dependency service temporarily being offline
or otherwise unavailable, e.g. package downloads. In this case you can try to
update your pull requests to rerun the tests later as described below.

You can update your pull requests by pushing new commits or force-pushing
changes to existing commits. Force-pushing an amended commit without any
actual content changed also allows you to retrigger the tests for that commit.

When you adjust your pull requests after review, consider squashing the
commits so that we can review the full updated version more easily.

A pull request sent to the project might get labeled `needs-votes` by a
project maintainer. This label means that in addition to meeting all other
checks and qualifications this pull request must also receive more "votes" of
user support. More signs that people want this to happen. It could be in the
form of messages saying so, or thumbs-up reactions on GitHub.

## When the pull request is approved

If it does not seem to get approved when you think it is ready - feel free to
ask for approval.

Once your pull request has been approved it can be merged by a maintainer.

For new features, or changes, we require that the *feature window* is open for
the pull request to be merged. This is typically a three week period that
starts ten days after a previous release. New features submitted as pull
requests while the window is closed have to wait until it opens to get
merged.

If time passes without your approved pull request gets merged: feel free to
ask what more you can do to make it happen.

## Making quality changes

Make the patch against as recent source versions as possible.

If you have followed the tips in this document and your patch still has not
been incorporated or responded to after some weeks, consider resubmitting it
to the list or better yet: change it to a pull request.

## Commit messages

How to write git commit messages in the curl project.

    ---- start ----
    [area]: [short line describing the main effect]
           -- empty line --
    [full description, no wider than 72 columns that describes as much as
    possible as to why this change is made, and possibly what things
    it fixes and everything else that is related,
    -- end --

The first line is a succinct description of the change and should ideally work
as a single line in the RELEASE NOTES.

- use the imperative, present tense: **change** not "changed" nor "changes"
- do not capitalize the first letter
- no period (.) at the end

The `[area]` in the first line can be `http2`, `cookies`, `openssl` or
similar. There is no fixed list to select from but using the same "area" as
other related changes could make sense.

## Commit message keywords

Use the following ways to improve the message and provide pointers to related
work.

- `Follow-up to {shorthash}` - if this fixes or continues a previous commit;
  add a `Ref:` that commit's PR or issue if it is not a small, obvious fix;
  followed by an empty line

- `Bug: URL` to the source of the report or more related discussion; use
  `Fixes` for GitHub issues instead when that is appropriate.

- `Approved-by: John Doe` - credit someone who approved the PR.

- `Authored-by: John Doe` - credit the original author of the code; only use
  this if you cannot use `git commit --author=...`.

- `Signed-off-by: John Doe` - we do not use this, but do not bother removing
  it.

- `whatever-else-by:` credit all helpers, finders, doers; try to use one of
  the following keywords if at all possible, for consistency: `Acked-by:`,
  `Assisted-by:`, `Co-authored-by:`, `Found-by:`, `Reported-by:`,
  `Reviewed-by:`, `Suggested-by:`, `Tested-by:`.

- `Ref: #1234` - if this is related to a GitHub issue or PR, possibly one that
  has already been closed.

- `Ref: URL` to more information about the commit; use `Bug:` instead for a
  reference to a bug on another bug tracker.

- `Fixes #1234` - if this fixes a GitHub issue; GitHub closes the issue once
  this commit is merged.

- `Closes #1234` - if this merges a GitHub PR; GitHub closes the PR once this
  commit is merged.

Do not forget to use commit with `--author` if you commit someone else's work,
and make sure that you have your own user and email setup correctly in git
before you commit.

Add whichever header lines as appropriate, with one line per person if more
than one person was involved. There is no need to credit yourself unless you
are using `--author` which hides your identity. Do not include people's email
addresses in headers to avoid spam, unless they are already public from a
previous commit; saying `{userid} on github` is OK.

## Push Access

If you are a frequent contributor, you may be given push access to the git
repository and then you are able to push your changes straight into the git
repository instead of sending changes as pull requests or by mail as patches.

Feel free to ask for this, if this is what you want. You are required to have
posted several high quality patches first, before you can be granted push
access.

## Useful resources

- [Webinar on getting code into curl](https://youtu.be/QmZ3W1d6LQI)

# Update copyright and license information

There is a CI job called **REUSE compliance / check** that runs on every pull
request and commit to verify that the *REUSE state* of all files are still
fine.

This means that all files need to have their license and copyright information
clearly stated. Ideally by having the standard curl source code header, with
the `SPDX-License-Identifier` included. If the header does not work, you can
use a smaller header or add the information for a specific file to the
`REUSE.toml` file.

You can manually verify the copyright and compliance status by running the
[REUSE helper tool](https://github.com/fsfe/reuse-tool): `reuse lint`

# On AI use in curl

Guidelines for AI use when contributing to curl.

## For security reports and other issues

If you asked an AI tool to find problems in curl, you **must** make sure to
reveal this fact in your report.

You must also double-check the findings carefully before reporting them to us
to validate that the issues are indeed existing and working exactly as the AI
says. AI-based tools frequently generate inaccurate or fabricated results.

Further: it is *rarely* a good idea to copy and paste an AI generated report
to the project. Those generated reports typically are too wordy and rarely to
the point (in addition to the common fabricated details). If you actually find
a problem with an AI and you have verified it yourself to be true: write the
report yourself and explain the problem as you have learned it. This makes
sure the AI-generated inaccuracies and invented issues are filtered out early
before they waste more people's time.

As we take security reports seriously, we investigate each report with
priority. This work is both time and energy consuming and pulls us away from
doing other meaningful work. Fake and otherwise made up security problems
effectively prevent us from doing real project work and make us waste time and
resources.

We ban users immediately who submit made up fake reports to the project.

## For pull requests

When contributing content to the curl project, you give us permission to use
it as-is and you must make sure you are allowed to distribute it to us. By
submitting a change to us, you agree that the changes can and should be
adopted by curl and get redistributed under the curl license. Authors should
be explicitly aware that the burden is on them to ensure no unlicensed code is
submitted to the project.

This is independent if AI is used or not.

When contributing a pull request you should of course always make sure that
the proposal is good quality and a best effort that follows our guidelines. A
basic rule of thumb is that if someone can spot that the contribution was made
with the help of AI, you have more work to do.

We can accept code written with the help of AI into the project, but the code
must still follow coding standards, be written clearly, be documented, feature
test cases and adhere to all the normal requirements we have.

## For translation

Translation services help users write reports, texts and documentation in
non-native languages and we encourage and welcome such contributors and
contributions.

As AI-based translation tools sometimes have a way to make the output sound a
little robotic and add an "AI tone" to the text, you may want to consider
mentioning that you used such a tool. Failing to do so risks that maintainers
wrongly dismiss translated texts as AI slop.
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl-config
Section: 1
Source: curl-config
See-also:
  - curl (1)
Added-in: 7.7.2
---

# NAME

curl-config - Get information about a libcurl installation

# SYNOPSIS

**curl-config [options]**

# DESCRIPTION

**curl-config**
displays information about the curl and libcurl installation.

# OPTIONS

## `--ca`

Displays the built-in path to the CA cert bundle this libcurl uses.

## `--cc`

Displays the compiler used to build libcurl.

## `--cflags`

Set of compiler options (CFLAGS) to use when compiling files that use
libcurl. Currently that is only the include path to the curl include files.

## `--checkfor [version]`

Specify the oldest possible libcurl version string you want, and this script
returns 0 if the current installation is new enough or it returns 1 and
outputs a text saying that the current version is not new enough. (Added in
7.15.4)

## `--configure`

Displays the arguments given to configure when building curl.

## `--feature`

Lists what particular main features the installed libcurl was built with. At
the time of writing, this list may include SSL, KRB4 or IPv6. Do not assume
any particular order. The keywords are separated by newlines. There may be
none, one, or several keywords in the list.

## `--help`

Displays the available options.

## `--libs`

Shows the complete set of libs and other linker options you need in order to
link your application with libcurl.

## `--prefix`

This is the prefix used when libcurl was installed. libcurl is then installed
in $prefix/lib and its header files are installed in $prefix/include and so
on. The prefix is set with `configure --prefix`.

## `--protocols`

Lists what particular protocols the installed libcurl was built to support. At
the time of writing, this list may include HTTP, HTTPS, FTP, FTPS, FILE,
TELNET, LDAP, DICT and many more. Do not assume any particular order. The
protocols are listed using uppercase and are separated by newlines. There may
be none, one, or several protocols in the list. (Added in 7.13.0)

## `--ssl-backends`

Lists the SSL backends that were enabled when libcurl was built. It might be
no, one or several names. If more than one name, they appear comma-separated.
(Added in 7.58.0)

## `--static-libs`

Shows the complete set of libs and other linker options you need in order to
link your application with libcurl statically. (Added in 7.17.1)

## `--version`

Outputs version information about the installed libcurl.

## `--vernum`

Outputs version information about the installed libcurl, in numerical mode.
This shows the version number, in hexadecimal, using 8 bits for each part:
major, minor, and patch numbers. This makes libcurl 7.7.4 appear as 070704 and
libcurl 12.13.14 appear as 0c0d0e... Note that the initial zero might be
omitted. (This option was broken in the 7.15.0 release.)

# EXAMPLES

What linker options do I need when I link with libcurl?

    $ curl-config --libs

What compiler options do I need when I compile using libcurl functions?

    $ curl-config --cflags

How do I know if libcurl was built with SSL support?

    $ curl-config --feature | grep SSL

What's the installed libcurl version?

    $ curl-config --version

How do I build a single file with a one-line command?

    $ `curl-config --cc --cflags` -o example source.c `curl-config --libs`
<!--
Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.

SPDX-License-Identifier: curl
-->

# Code defines to disable features and protocols

## `CURL_DISABLE_ALTSVC`

Disable support for Alt-Svc: HTTP headers.

## `CURL_DISABLE_BINDLOCAL`

Disable support for binding the local end of connections.

## `CURL_DISABLE_COOKIES`

Disable support for HTTP cookies.

## `CURL_DISABLE_BASIC_AUTH`

Disable support for the Basic authentication methods.

## `CURL_DISABLE_BEARER_AUTH`

Disable support for the Bearer authentication methods.

## `CURL_DISABLE_DIGEST_AUTH`

Disable support for the Digest authentication methods.

## `CURL_DISABLE_KERBEROS_AUTH`

Disable support for the Kerberos authentication methods.

## `CURL_DISABLE_NEGOTIATE_AUTH`

Disable support for the negotiate authentication methods.

## `CURL_DISABLE_AWS`

Disable **aws-sigv4** support.

## `CURL_DISABLE_HTTPSIG`

Disable RFC 9421 HTTP Message Signatures support.

## `CURL_DISABLE_CA_SEARCH`

Disable unsafe CA bundle search in PATH on Windows.

## `CURL_DISABLE_DICT`

Disable the DICT protocol

## `CURL_DISABLE_DOH`

Disable DNS-over-HTTPS

## `CURL_DISABLE_FILE`

Disable the FILE protocol

## `CURL_DISABLE_FORM_API`

Disable the form API

## `CURL_DISABLE_FTP`

Disable the FTP (and FTPS) protocol

## `CURL_DISABLE_GETOPTIONS`

Disable the `curl_easy_options()` API calls that lets users get information
about existing options to `curl_easy_setopt()`.

## `CURL_DISABLE_GOPHER`

Disable the GOPHER protocol.

## `CURL_DISABLE_HEADERS_API`

Disable the HTTP header API.

## `CURL_DISABLE_HSTS`

Disable the HTTP Strict Transport Security support.

## `CURL_DISABLE_HTTP`

Disable the HTTP(S) protocols. Note that this then also disable HTTP proxy
support.

## `CURL_DISABLE_HTTP_AUTH`

Disable support for all HTTP authentication methods.

## `CURL_DISABLE_IMAP`

Disable the IMAP(S) protocols.

## `CURL_DISABLE_LDAP`

Disable the LDAP(S) protocols.

## `CURL_DISABLE_LDAPS`

Disable the LDAPS protocol.

## `CURL_DISABLE_LIBCURL_OPTION`

Disable the --libcurl option from the curl tool.

## `CURL_DISABLE_MIME`

Disable MIME support.

## `CURL_DISABLE_MQTT`

Disable MQTT support.

## `CURL_DISABLE_NETRC`

Disable the netrc parser.

## `CURL_DISABLE_OPENSSL_AUTO_LOAD_CONFIG`

Disable the auto load config support in the OpenSSL backend.

## `CURL_DISABLE_PARSEDATE`

Disable date parsing

## `CURL_DISABLE_POP3`

Disable the POP3 protocol

## `CURL_DISABLE_PROGRESS_METER`

Disable the built-in progress meter

## `CURL_DISABLE_PROXY`

Disable support for proxies

## `CURL_DISABLE_IPFS`

Disable the IPFS/IPNS protocols. This affects the curl tool only, where
IPFS/IPNS protocol support is implemented.

## `CURL_DISABLE_RTSP`

Disable the RTSP protocol.

## `CURL_DISABLE_SHA512_256`

Disable the SHA-512/256 hash algorithm.

## `CURL_DISABLE_SHUFFLE_DNS`

Disable the shuffle DNS feature

## `CURL_ENABLE_SMB`

Enable the SMB(S) protocols

## `CURL_DISABLE_SMTP`

Disable the SMTP(S) protocols

## `CURL_DISABLE_SOCKETPAIR`

Disable the use of `socketpair()` internally to allow waking up and canceling
`curl_multi_poll()`.

## `CURL_DISABLE_TELNET`

Disable the TELNET protocol

## `CURL_DISABLE_TFTP`

Disable the TFTP protocol

## `CURL_DISABLE_TYPECHECK`

Disable `curl_easy_setopt()`/`curl_easy_getinfo()` type checking.

Useful to improve build performance for the `tests/libtest` test tool.

## `CURL_DISABLE_VERBOSE_STRINGS`

Disable verbose strings and error messages.

## `CURL_DISABLE_WEBSOCKETS`

Disable the WebSocket protocols.
<!--
Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.

SPDX-License-Identifier: curl
-->

# curldown

A markdown-like syntax for libcurl man pages.

## Purpose

A text format for writing libcurl documentation in the shape of man pages.

Make it easier for users to contribute and write documentation. A format that
is easier on the eye in its source format.

Make it harder to do syntactical mistakes.

Use a format that allows creating man pages that end up looking exactly like
the man pages did when we wrote them in nroff format.

Take advantage of the fact that people these days are accustomed to markdown
by using a markdown-like syntax.

This allows us to fix issues in the nroff format easier since now we generate
them. For example: escaping minus to prevent them from being turned into
Unicode by man.

Generate nroff output that looks (next to) *identical* to the previous files,
so that the look, existing test cases, HTML conversions, existing
infrastructure etc remain mostly intact.

Contains meta-data in a structured way to allow better output (for example the
see also information) and general awareness of what the file is about.

## File extension

Since curldown looks similar to markdown, we use `.md` extensions on the
files.

## Conversion

Convert **from curldown to nroff** with `cd2nroff`. Generates nroff man pages.

Convert **from nroff to curldown** with `nroff2cd`. This is only meant to be
used for the initial conversion to curldown and should ideally never be needed
again.

Convert, check or clean up an existing curldown to nicer, better, cleaner
curldown with **cd2cd**.

Mass-convert all curldown files to nroff in specified directories with
`cdall`:

    cdall [dir1] [dir2] [dir3] ..

## Known issues

The `cd2nroff` tool does not yet handle *italics* or **bold** where the start
and the end markers are used on separate lines.

The `nroff2cd` tool generates code style quotes for all `.fi` sections since
the nroff format does not carry a distinction.

# Format

Each curldown starts with a header with meta-data:

    ---
    c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
    SPDX-License-Identifier: curl
    Title: CURLOPT_AWS_SIGV4
    Section: 3
    Source: libcurl
    Protocol:
      - HTTP
    See-also:
      - CURLOPT_HEADEROPT (3)
      - CURLOPT_HTTPAUTH (3)
    TLS-backend:
      - [name]
    Added-in: [version or "n/a"]
    ---

All curldown files *must* have all the headers present and at least one
`See-also:` entry specified.

If the man page is for section 3 (library related). The `Protocol` list must
contain at least one protocol, which can be `*` if the option is virtually for
everything. If `*` is used, it must be the only listed protocol. Recognized
protocols are either URL schemes (in uppercase), `TLS` or `TCP`.

If the `Protocol` list contains `TLS`, then there must also be a `TLS-backend`
list, specifying `All` or a list of what TLS backends that work with this
option. The available TLS backends are:

- `GnuTLS`
- `mbedTLS`
- `OpenSSL` (also covers AmiSSL, AWS-LC, BoringSSL, LibreSSL and quictls)
- `rustls`
- `Schannel`
- `wolfSSL`
- `All`: all TLS backends

Following the header in the file, is the manual page using markdown-like
syntax:

~~~
    # NAME
    a page - this is a page describing something

    # SYNOPSIS
    ~~~c
    #include <curl/curl.h>

    CURLcode curl_easy_setopt(CURL *handle, CURLOPT_AWS_SIGV4, char *param);
    ~~~
~~~

Quoted source code should start with `~~~c` and end with `~~~` while regular
quotes can start with `~~~` or be indented with 4 spaces.

Headers at top-level `#` get converted to `.SH`.

`nroff2cd` supports the `##` next level header which gets converted to `.IP`.

Write bold words or phrases within `**` like:

    This is a **bold** word.

Write italics like:

    This is *italics*.

Due to how man pages do not support backticks especially formatted, such
occurrences in the source are instead using italics in the generated output:

    This `word` appears in italics.

When generating the nroff output, the tooling removes superfluous newlines,
meaning they can be used freely in the source file to make the text more
readable.

To make sure curldown documents render correctly as markdown, all literal
occurrences of `<` or `>` need to be escaped by a leading backslash.

## Generating contents

`# %PROTOCOLS%` - inserts a **PROTOCOLS** section based on the metadata
provided in the header.

`# %AVAILABILITY%` - inserts an **AVAILABILITY** section based on the metadata
provided in the header.

## Symbols

All mentioned curl symbols that have their own man pages, like
`curl_easy_perform(3)` are automatically rendered using italics in the output
without having to enclose it with asterisks. This helps ensuring that they get
converted to links properly later in the HTML version on the website, as
converted with `roffit`. This makes the curldown text easier to read even when
mentioning many curl symbols.

This auto-linking works for patterns matching `(lib|)curl[^ ]*(3)`.
<!--
Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.

SPDX-License-Identifier: curl
-->

# curl dependencies

Supported minimum versions of libs and build tools.

## Portability

We write curl and libcurl to compile with C89 compilers on 32-bit and up
machines. Most of libcurl assumes more or less POSIX compliance but that is
not a requirement. The compiler must support a 64-bit integer type as well as
supply a stdint.h header file that defines C99-style fixed-width integer types
like uint32_t.

We write libcurl to build and work with lots of third party tools, and we
want it to remain functional and buildable with these and later versions
(older versions may still work but is not what we work hard to maintain):

## Dependencies

We aim to support these or later versions:

- brotli        1.0.0 (2017-09-21)
- c-ares        1.16.0 (2020-03-13)
- GnuTLS        3.6.5 (2018-12-01)
- libidn2       2.0.0 (2017-03-29)
- libgsasl      1.6.0 (2010-12-14)
- libpsl        0.16.0 (2016-12-10)
- LibreSSL      2.9.1 (2019-04-21)
- libssh        0.9.0 (2019-06-28)
- libssh2       1.9.0 (2019-06-20)
- mbedTLS       3.2.0 (2022-07-11)
- MIT Kerberos  1.3 (2003-07-31)
- nettle        3.4.1 (2018-12-04)
- nghttp2       1.15.0 (2016-09-25)
- nghttp3       1.0.0 (2023-10-15)
- ngtcp2        1.0.0 (2023-10-15), with OpenSSL 3.5.0+: 1.12.0 (2025-04-16)
- OpenLDAP      2.0 (2000-08-01)
- OpenSSL       3.0.0 (2021-09-07)
- quiche        0.20.0 (2023-12-12)
- Windows       Vista 6.0 (2006-11-08 - 2012-04-10)
- wolfSSL       5.0.0 (2021-11-01)
- zlib          1.2.5.2 (2011-12-11)
- zstd          1.0 (2016-08-31)

## Build tools

When writing code (mostly for generating stuff included in release tarballs)
we use a few "build tools" and we make sure that we remain functional with
these or later versions:

- clang-tidy     17.0.0 (2023-09-19), recommended: 19.1.0 (2024-09-17)
- cmake          3.18 (2020-07-15)
- GNU autoconf   2.59 (2003-11-06)
- GNU automake   1.7 (2002-09-25)
- GNU libtool    1.4.2 (2001-09-11)
- GNU m4         1.4 (2007-09-21)
- mingw-w64      3.0 (2013-09-20)
- perl           5.8 (2002-07-19), on Windows: 5.22 (2015-06-01)
- Visual Studio  2010 10.0 (2010-04-12 - 2020-07-14)

## Testing

Certain tests require the following packages to operate. In some cases, tests
that do not find the necessary requirements are automatically skipped.

- OpenSSL        (see above)
- nghttp2        (see above)
- OpenSSH
- perl           (see above)
- pytest
- Python         3.8 (2019-10-14)
- stunnel
<!--
Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.

SPDX-License-Identifier: curl
-->

# Items to be removed from future curl releases

If any of these deprecated features is a cause for concern for you, please
email the
[curl-library mailing list](https://lists.haxx.se/listinfo/curl-library)
as soon as possible and explain to us why this is a problem for you and
how your use case cannot be satisfied properly using a workaround.

## drop SMB support

The SMB protocol has weak security and is rarely used these days.

SMB support gets removed in September 2026.

## drop NTLM support

The NTLM authentication method has weak security and is rarely used these
days. It has been deprecated by Microsoft and does not work over HTTP/2 or
HTTP/3.

NTLM support gets removed in September 2026

## Local crypto implementations

Since the dawn of time, curl bundles code for a few crypto and hash algorithms
in order to enable functionality for builds without TLS libraries. This list
includes MD4, MD5, SHA256, SHA256_512 and perhaps something more.

Meanwhile, curl is almost always built to use a TLS/crypto library which for
sure has better maintained and better performing versions of these algorithms.

Also, the local curl implementations are not as widely tested since curl
builds without TLS are rare.

Since these implementations are going away, a good idea is to verify ahead of
time that builds using your preferred TLS library use the crypto functions
provided by that library and are not bundled by curl.

The removal of local crypto functions subsequently disables some functions in
future curl versions when built without TLS support. For example Digest.

Local crypto gets removed in October 2026.

## HTTP/2 Server Push

This protocol feature has been deprecated in specifications, by major browsers,
and in server implementations. It was never supported by the curl command line
tool, only by libcurl.

We estimate that barely any libcurl users still use this feature.

HTTP/2 Server Push gets removed in March 2027.

## Past removals

- axTLS (removed in 7.63.0)
- Pipelining (removed in 7.65.0)
- PolarSSL (removed in 7.69.0)
- NPN (removed in 7.86.0)
- Support for systems without 64-bit data types (removed in 8.0.0)
- NSS (removed in 8.3.0)
- gskit (removed in 8.3.0)
- MinGW v1 (removed in 8.4.0)
- NTLM_WB (removed in 8.8.0)
- space-separated `NOPROXY` patterns (removed in 8.9.0)
- hyper (removed in 8.12.0)
- Support for Visual Studio 2005 and older (removed in 8.13.0)
- Secure Transport (removed in 8.15.0)
- BearSSL (removed in 8.15.0)
- msh3 (removed in 8.16.0)
- winbuild build system (removed in 8.17.0)
- Windows CE (removed in 8.18.0)
- Support for Visual Studio 2008 (removed in 8.18.0)
- OpenSSL 1.1.1 and older (removed in 8.18.0)
- Support for Windows XP (removed in 8.19.0)
- OpenSSL-QUIC (removed in 8.19.0)
- CMake 3.17 and older (removed in 8.20.0)
- RTMP (removed in 8.20.0)
- SMB (became opt-in in 8.20.0)
- NTLM (became opt-in in 8.20.0)
- c-ares < 1.16.0 (removed in 8.20.0)
- TLS-SRP (removed in 8.22.0)
<!--
Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.

SPDX-License-Identifier: curl
-->

# curl distros

<!-- markdown-link-check-disable -->

Lots of organizations distribute curl packages to end users. This is a
collection of pointers to where to learn more about curl on and with each
distro. Those marked *Rolling Release* typically run the latest version of curl
and are therefore less likely to have back-ported patches to older versions.

We discuss curl distro issues, patches and collaboration on the [curl-distros
mailing list](https://lists.haxx.se/listinfo/curl-distros) ([list
archives](https://curl.se/mail/list.cgi?list=curl-distros)).

## AlmaLinux

- curl package source and patches: https://git.almalinux.org/rpms/curl/
- curl issues: https://bugs.almalinux.org/view_all_bug_page.php click Category and choose curl
- curl security: https://errata.almalinux.org/ search for curl

## Alpine Linux

- curl: https://pkgs.alpinelinux.org/package/edge/main/x86_64/curl
- curl issues: https://gitlab.alpinelinux.org/alpine/aports/-/issues
- curl security: https://security.alpinelinux.org/srcpkg/curl
- curl package source and patches: https://gitlab.alpinelinux.org/alpine/aports/-/tree/master/main/curl

## Alt Linux

- curl: https://packages.altlinux.org/en/search/?q=curl
- curl issues: https://packages.altlinux.org/en/sisyphus/srpms/curl/issues/
- curl patches: https://git.altlinux.org/gears/c/curl.git?p=curl.git;a=tree;f=.gear

## Arch Linux

*Rolling Release*

- curl: https://archlinux.org/packages/core/x86_64/curl/
- curl issues: https://gitlab.archlinux.org/archlinux/packaging/packages/curl/-/issues
- curl security: https://security.archlinux.org/package/curl
- curl wiki: https://wiki.archlinux.org/title/CURL

## Buildroot

*Rolling Release*

- curl package source and patches: **missing URL**
- curl issues: **missing URL**

## Chimera

- curl package source and patches: https://github.com/chimera-linux/cports/tree/master/main/curl

## Clear Linux

*Rolling Release*

- curl: https://github.com/clearlinux-pkgs/curl
- curl issues: https://github.com/clearlinux/distribution/issues

## Conary

- curl: https://github.com/conan-io/conan-center-index/tree/master/recipes/libcurl
- curl issues: https://github.com/conan-io/conan-center-index/issues
- curl patches: https://github.com/conan-io/conan-center-index/tree/master/recipes/libcurl (in `all/patches/*`, if any)

## conda-forge

- curl: https://github.com/conda-forge/curl-feedstock
- curl issues: https://github.com/conda-forge/curl-feedstock/issues

## CRUX

- curl: https://crux.nu/portdb/?a=search&q=curl
- curl issues: https://git.crux.nu/ports/core/issues/?type=all&state=open&q=curl

## curl-for-win

(this is the official curl binaries for Windows shipped by the curl project)

*Rolling Release*

- curl: https://curl.se/windows/
- curl patches: https://github.com/curl/curl-for-win/blob/main/curl.patch (if any)
- build-specific issues: https://github.com/curl/curl-for-win/issues

Issues and patches for this are managed in the main curl project.

## Cygwin

- curl: https://cygwin.com/cgit/cygwin-packages/curl/tree/curl.cygport
- curl patches: https://cygwin.com/cgit/cygwin-packages/curl/tree
- curl issues: https://inbox.sourceware.org/cygwin/?q=s%3Acurl

## Cygwin (cross mingw64)

- mingw64-x86_64-curl: https://cygwin.com/cgit/cygwin-packages/mingw64-x86_64-curl/tree/mingw64-x86_64-curl.cygport
- mingw64-x86_64-curl patches: https://cygwin.com/cgit/cygwin-packages/mingw64-x86_64-curl/tree
- mingw64-x86_64-curl issues: https://inbox.sourceware.org/cygwin/?q=s%3Amingw64-x86_64-curl

## Debian

- curl: https://tracker.debian.org/pkg/curl
- curl issues: https://bugs.debian.org/cgi-bin/pkgreport.cgi?pkg=curl
- curl patches: https://udd.debian.org/patches.cgi?src=curl
- curl patches: https://salsa.debian.org/debian/curl (in debian/* branches, inside the folder debian/patches)

## Fedora

- curl: https://src.fedoraproject.org/rpms/curl
- curl issues: [bugzilla](https://bugzilla.redhat.com/buglist.cgi?bug_status=NEW&bug_status=ASSIGNED&classification=Fedora&product=Fedora&product=Fedora%20EPEL&component=curl)
- curl patches: [list of patches in package git](https://src.fedoraproject.org/rpms/curl/tree/rawhide)

## FreeBSD

- curl: https://cgit.freebsd.org/ports/tree/ftp/curl
- curl patches: https://cgit.freebsd.org/ports/tree/ftp/curl
- curl issues: https://bugs.freebsd.org/bugzilla/buglist.cgi?bug_status=__open__&order=Importance&product=Ports%20%26%20Packages&query_format=advanced&short_desc=curl&short_desc_type=allwordssubstr

## Gentoo Linux

*Rolling Release*

- curl: https://packages.gentoo.org/packages/net-misc/curl
- curl issues: https://bugs.gentoo.org/buglist.cgi?quicksearch=net-misc/curl
- curl package sources and patches: https://gitweb.gentoo.org/repo/gentoo.git/tree/net-misc/curl/

## GNU Guix

*Rolling Release*

- curl: https://git.savannah.gnu.org/gitweb/?p=guix.git;a=blob;f=gnu/packages/curl.scm;hb=HEAD
- curl issues: https://issues.guix.gnu.org/search?query=curl

## Haiku

- curl: https://github.com/haikuports/haikuports/tree/master/net-misc/curl
- curl issues: https://github.com/haikuports/haikuports/issues
- curl patches: https://github.com/haikuports/haikuports/tree/master/net-misc/curl/patches (if any)

## Homebrew

*Rolling Release*

- curl: https://formulae.brew.sh/formula/curl

Homebrew's policy is that all patches and issues should be submitted upstream
unless it is specific to Homebrew's way of packaging software.

## LibreELEC

- curl: https://github.com/LibreELEC/LibreELEC.tv/blob/master/packages/web/curl/
- curl issues: https://github.com/LibreELEC/LibreELEC.tv/issues?q=is%3Aissue%20state%3Aopen%20curl
- curl patches: https://github.com/LibreELEC/LibreELEC.tv/blob/master/packages/web/curl/patches/

## MacPorts

*Rolling Release*

- curl: https://github.com/macports/macports-ports/tree/master/net/curl
- curl issues: https://trac.macports.org/query?0_port=curl&0_port_mode=%7E&0_status=%21closed
- curl patches: https://github.com/macports/macports-ports/tree/master/net/curl/files

## Mageia

- curl: https://svnweb.mageia.org/packages/cauldron/curl/current/SPECS/curl.spec?view=markup
- curl issues: https://bugs.mageia.org/buglist.cgi?bug_status=NEW&bug_status=UNCONFIRMED&bug_status=NEEDINFO&bug_status=UPSTREAM&bug_status=ASSIGNED&component=RPM%20Packages&f1=cf_rpmpkg&list_id=176576&o1=casesubstring&product=Mageia&query_format=advanced&v1=curl
- curl patches: https://svnweb.mageia.org/packages/cauldron/curl/current/SOURCES/
- curl patches in stable distro releases: https://svnweb.mageia.org/packages/updates/9/curl/current/SOURCES/
- curl security: https://advisories.mageia.org/src_curl.html

## MSYS2

*Rolling Release*

- curl: https://github.com/msys2/MSYS2-packages/tree/master/curl
- curl issues: https://github.com/msys2/MSYS2-packages/issues
- curl patches: https://github.com/msys2/MSYS2-packages/tree/master/curl (`*.patch`)

## MSYS2 (mingw-w64)

*Rolling Release*

- curl: https://github.com/msys2/MINGW-packages/tree/master/mingw-w64-curl
- curl issues: https://github.com/msys2/MINGW-packages/issues
- curl patches: https://github.com/msys2/MINGW-packages/tree/master/mingw-w64-curl (`*.patch`)

## Muldersoft

*Rolling Release*

- curl: https://github.com/lordmulder/curl-build-win32
- curl issues: https://github.com/lordmulder/curl-build-win32/issues
- curl patches: https://github.com/lordmulder/curl-build-win32/tree/master/patch

## NixOS

- curl: https://github.com/NixOS/nixpkgs/blob/nixos-unstable/pkgs/by-name/cu/curlMinimal/package.nix
- curl issues: https://github.com/NixOS/nixpkgs

nixpkgs is the package repository used by the NixOS Linux distribution, but
can also be used on other distributions

## OmniOS

- curl: https://github.com/omniosorg/omnios-build/tree/master/build/curl
- curl issues: https://github.com/omniosorg/omnios-build/issues
- curl patches: https://github.com/omniosorg/omnios-build/tree/master/build/curl/patches

## OpenIndiana

- curl: https://github.com/OpenIndiana/oi-userland/tree/oi/hipster/components/web/curl
- curl issues: https://www.illumos.org/projects/openindiana/issues
- curl patches: https://github.com/OpenIndiana/oi-userland/tree/oi/hipster/components/web/curl/patches

## OpenSUSE

- curl source and patches: https://build.opensuse.org/package/show/openSUSE%3AFactory/curl

## Oracle Solaris

- curl: https://github.com/oracle/solaris-userland/tree/master/components/curl
- curl issues: https://support.oracle.com/ (requires support contract)
- curl patches: https://github.com/oracle/solaris-userland/tree/master/components/curl/patches

## OpenBSD

- curl: https://github.com/openbsd/ports/tree/master/net/curl
- curl issues: https://www.openbsd.org/mail.html (ports mailing list)
- curl patches: https://github.com/openbsd/ports/tree/master/net/curl/patches

## OpenEmbedded / Yocto Project

*Rolling Release*

- curl: https://layers.openembedded.org/layerindex/recipe/5765/
- curl issues: https://bugzilla.yoctoproject.org/
- curl patches: https://git.openembedded.org/openembedded-core/tree/meta/recipes-support/curl

## PLD Linux

- curl package source and patches: https://github.com/pld-linux/curl
- curl issues: https://bugs.launchpad.net/pld-linux?field.searchtext=curl&search=Search&field.status%3Alist=NEW&field.status%3Alist=INCOMPLETE_WITH_RESPONSE&field.status%3Alist=INCOMPLETE_WITHOUT_RESPONSE&field.status%3Alist=CONFIRMED&field.status%3Alist=TRIAGED&field.status%3Alist=INPROGRESS&field.status%3Alist=FIXCOMMITTED&field.assignee=&field.bug_reporter=&field.omit_dupes=on&field.has_patch=&field.has_no_package=

## pkgsrc

- curl: https://github.com/NetBSD/pkgsrc/tree/trunk/www/curl
- curl issues: https://github.com/NetBSD/pkgsrc/issues
- curl patches: https://github.com/NetBSD/pkgsrc/tree/trunk/www/curl/patches

## Red Hat Enterprise Linux / CentOS Stream

- curl: https://kojihub.stream.centos.org/koji/packageinfo?packageID=217
- curl issues: https://issues.redhat.com/secure/CreateIssueDetails!init.jspa?pid=12332745&issuetype=1&components=12377466&priority=10300
- curl patches: https://gitlab.com/redhat/centos-stream/rpms/curl

## Rocky Linux

- curl: https://git.rockylinux.org/staging/rpms/curl/-/blob/r9/SPECS/curl.spec
- curl issues: https://bugs.rockylinux.org/
- curl patches: https://git.rockylinux.org/staging/rpms/curl/-/tree/r9/SOURCES

## SerenityOS

- curl: https://github.com/SerenityOS/serenity/tree/master/Ports/curl
- curl issues: https://github.com/SerenityOS/serenity/issues?q=label%3Aports
- curl patches: https://github.com/SerenityOS/serenity/tree/master/Ports/curl/patches

## SmartOS

- curl: https://github.com/TritonDataCenter/illumos-extra/tree/master/curl
- curl issues: https://github.com/TritonDataCenter/illumos-extra/issues
- curl patches: https://github.com/TritonDataCenter/illumos-extra/tree/master/curl/Patches

## SPACK

- curl package source and patches: https://github.com/spack/spack/tree/develop/var/spack/repos/builtin/packages/curl

## vcpkg

*Rolling Release*

- curl: https://github.com/microsoft/vcpkg/tree/master/ports/curl
- curl issues: https://github.com/microsoft/vcpkg/issues
- curl patches: https://github.com/microsoft/vcpkg/tree/master/ports/curl (`*.patch`)

## Void Linux

*Rolling Release*

- curl: https://github.com/void-linux/void-packages/tree/master/srcpkgs/curl
- curl issues: https://github.com/void-linux/void-packages/issues
- curl patches: https://github.com/void-linux/void-packages/tree/master/srcpkgs/curl/patches

## Wolfi

*Rolling Release*

- curl: https://github.com/wolfi-dev/os/blob/main/curl.yaml
<!--
Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.

SPDX-License-Identifier: curl
-->

# How to determine if an early patch release is warranted

In the curl project we do releases every 8 weeks. Unless we break the cycle
and do an early patch release.

We do frequent releases partly to always have the next release "not too far
away".

## Bugfix

During the release cycle, and especially in the beginning of a new cycle (the
so-called "cool down" period), there are times when a bug is reported and
after it has been subsequently fixed correctly, the question might be asked:
is this bug and associated fix important enough for an early patch release?

The question can only be properly asked when a fix has been created and landed
in the git master branch.

## Early release

An early patch release means that we ship a new, complete and full release
called `major.minor.patch` where the `patch` part is increased by one since
the previous release. A curl release is a curl release. There is no small or
big and we never ship stand-alone separate patches. There is only "release".

## Questions to ask

- Is there a security advisory rated high or critical?
- Is there a data corruption bug?
- Did the bug cause an API/ABI breakage?
- Does the problem annoy a significant share of the user population?

If the answer is yes to one or more of the above, an early release might be
warranted.

More questions to ask ourselves when doing the assessment if the answers to
the three ones above are all 'no'.

- Does the bug cause curl to prematurely terminate?
- How common is the affected buggy option/feature/protocol/platform to get
  used?
- How large is the estimated impacted user base?
- Does the bug block something crucial for applications or other adoption of
  curl "out there" ?
- Does the bug cause problems for curl developers or others on "the curl
  team" ?
- Is the bug limited to the curl tool only? That might have a smaller impact
  than a bug also present in libcurl.
- Is there a (decent) workaround?
- Is it a regression? Is the bug introduced in this release?
- Can the bug be fixed "easily" by applying a patch?
- Does the bug break the build? Most users do not build curl themselves.
- How long is it until the already scheduled next release?
- Can affected users safely revert to a former release until the next
  scheduled release?
- Is it a performance regression with no functionality side-effects? If so it
  has to be substantial.

## If an early release is deemed necessary

Unless done for security or similarly important reasons, an early release
should not be done within a week of the previous release.

This, to enable us to collect and bundle more fixes into the same release to
make the release more worthwhile for everyone and to allow more time for fixes
to settle and things to get tested. Getting a release in shape and done in
style is work that should not be rushed.
<!--
Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.

SPDX-License-Identifier: curl
-->

# Building curl with HTTPS-RR and ECH support

We have added support for ECH to curl. It can use HTTPS RRs published in the
DNS if curl uses DoH, or else can accept the relevant ECHConfigList values
from the command line. This works with AWS-LC, BoringSSL, OpenSSL, Rustls or
wolfSSL as the TLS provider.

This feature is EXPERIMENTAL. DO NOT USE IN PRODUCTION.

This should however provide enough of a proof-of-concept to prompt an informed
discussion about a good path forward for ECH support in curl.

## OpenSSL Build

To build OpenSSL 4.0.0+:

```sh
cd $HOME/code
git clone --depth 1 --branch openssl-4.0.0 https://github.com/openssl/openssl
cd openssl
./config --libdir=lib --prefix=$HOME/code/openssl-local-inst
...stuff...
make -j8
...more stuff...
make install_sw
...a little bit of stuff...
```

To build curl ECH-enabled, making use of the above:

```sh
cd $HOME/code
git clone --depth 1 https://github.com/curl/curl
cd curl
autoreconf -fi
LDFLAGS="-Wl,-rpath,$HOME/code/openssl-local-inst/lib/" ./configure --with-ssl=$HOME/code/openssl-local-inst --enable-ech
...lots of output...
WARNING: ECH is enabled but marked EXPERIMENTAL...
make
...lots more output...
```

If you do not get that WARNING at the end of the `configure` command, then
ECH is not enabled, so go back some steps and re-do whatever needs re-doing:-)
If you want to debug curl then you should add `--enable-debug` to the
`configure` command.

In a recent (2024-05-20) build on one machine, configure failed to find the
ECH-enabled SSL library, apparently due to the existence of
`$HOME/code/openssl-local-inst/lib/pkgconfig` as a directory containing
various settings. Deleting that directory worked around the problem but may
not be the best solution.

## Using ECH and DoH

curl supports using DoH for A/AAAA lookups so it was relatively easy to add
retrieval of HTTPS RRs in that situation. To use ECH and DoH together:

```sh
cd $HOME/code/curl
LD_LIBRARY_PATH=$HOME/code/openssl ./src/curl --ech true --doh-url https://one.one.one.one/dns-query https://defo.ie/ech-check.php
...
SSL_ECH_STATUS: success <img src="greentick-small.png" alt="good" /> <br/>
...
```

The output snippet above is within the HTML for the webpage, when things work.

The above works for these test sites:

```sh
https://defo.ie/ech-check.php
https://crypto.cloudflare.com/cdn-cgi/trace
https://tls-ech.dev/
```

The list above has 4 different server technologies, implemented by 3 different
parties, and includes a case (the port 8414 server) where HelloRetryRequest
(HRR) is forced.

We currently support the following new curl command line arguments/options:

- `--ech <config>` - the `config` value can be one of:
    - `false` says to not attempt ECH
    - `true` says to attempt ECH, if possible
    - `grease` if attempting ECH is not possible, then send a GREASE ECH extension
    - `hard` hard-fail the connection if ECH cannot be attempted
    - `ecl:<b64value>` a base64 encoded ECHConfigList, rather than one accessed from the DNS
    - `pn:<name>` override the `public_name` from an ECHConfigList

Note that in the above "attempt ECH" means the client emitting a TLS
ClientHello with a "real" ECH extension, but that does not mean that the
relevant server can succeed in decrypting, as things can fail for other
reasons.

## Supplying an ECHConfigList on the command line

To supply the ECHConfigList on the command line, you might need a bit of
cut-and-paste, e.g.:

```sh
dig +short https defo.ie
1 . ipv4hint=213.108.108.101 ech=AED+DQA8PAAgACD8WhlS7VwEt5bf3lekhHvXrQBGDrZh03n/LsNtAodbUAAEAAEAAQANY292ZXIuZGVmby5pZQAA
  ipv6hint=2a00:c6c0:0:116:5::10
```

Then paste the base64 encoded ECHConfigList onto the curl command line:

```sh
LD_LIBRARY_PATH=$HOME/code/openssl ./src/curl --ech ecl:AED+DQA8PAAgACD8WhlS7VwEt5bf3lekhHvXrQBGDrZh03n/LsNtAodbUAAEAAEAAQANY292ZXIuZGVmby5pZQAA \
  https://defo.ie/ech-check.php
...
SSL_ECH_STATUS: success <img src="greentick-small.png" alt="good" /> <br/>
...
```

The output snippet above is within the HTML for the webpage.

If you paste in the wrong ECHConfigList (it changes hourly for `defo.ie`) you
should get an error like this:

```sh
LD_LIBRARY_PATH=$HOME/code/openssl ./src/curl -vvv --ech ecl:AED+DQA8yAAgACDRMQo+qYNsNRNj+vfuQfFIkrrUFmM4vogucxKj/4nzYgAEAAEAAQANY292ZXIuZGVmby5pZQAA \
  https://defo.ie/ech-check.php
...
* OpenSSL/3.3.0: error:0A00054B:SSL routines::ech required
...
```

There is a reason to want this command line option - for use before publishing
an ECHConfigList in the DNS as per the Internet-draft [A well-known URI for
publishing ECHConfigList values](https://datatracker.ietf.org/doc/html/draft-ietf-tls-wkech/).

If you do use a wrong ECHConfigList value, then the server might return a
good value, via the `retry_configs` mechanism. You can see that value in
the verbose output, e.g.:

```sh
LD_LIBRARY_PATH=$HOME/code/openssl ./src/curl -vvv --ech ecl:AED+DQA8yAAgACDRMQo+qYNsNRNj+vfuQfFIkrrUFmM4vogucxKj/4nzYgAEAAEAAQANY292ZXIuZGVmby5pZQAA \
  https://defo.ie/ech-check.php
...
* ECH: retry_configs AQD+DQA8DAAgACBvYqJy+Hgk33wh/ZLBzKSPgwxeop7gvojQzfASq7zeZQAEAAEAAQANY292ZXIuZGVmby5pZQAA/g0APEMAIAAgXkT5r4cYs8z19q5rdittyIX
  8gfQ3ENW4wj1fVoiJZBoABAABAAEADWNvdmVyLmRlZm8uaWUAAP4NADw2ACAAINXSE9EdXzEQIJZA7vpwCIQsWqsFohZARXChgPsnfI1kAAQAAQABAA1jb3Zlci5kZWZvLmllAAD+DQA8c
  QAgACASeiD5F+UoSnVoHvA2l1EifUVMFtbVZ76xwDqmMPraHQAEAAEAAQANY292ZXIuZGVmby5pZQAA
* ECH: retry_configs for defo.ie from cover.defo.ie, 319
...
```

At that point, you could copy the base64 encoded value above and try again.
For now, this only works for the OpenSSL and AWS-LC/BoringSSL builds.

## Default settings

curl has various ways to configure default settings, e.g. in `$HOME/.curlrc`,
so one can set the DoH URL and enable ECH that way:

```sh
cat ~/.curlrc
doh-url=https://one.one.one.one/dns-query
silent
ech=true
```

Note that when you use the system's curl command (rather than our ECH-enabled
build), it is liable to warn that `ech` is an unknown option. If that is an
issue (e.g. if some script re-directs stdout and stderr somewhere) then adding
the `silent` line above seems to be a good enough fix. (Though of
course, yet another script could depend on non-silent behavior, so you may have
to figure out what you prefer yourself.) That seems to have changed with the
latest build, previously `silent=TRUE` was what I used in `~/.curlrc` but
now that seems to cause a problem, so that the following line(s) are ignored.

If you want to always use our OpenSSL build you can set `LD_LIBRARY_PATH`
in the environment:

```sh
export LD_LIBRARY_PATH=$HOME/code/openssl
```

When you do the above, there can be a mismatch between OpenSSL versions
for applications that check that. A `git push` for example fails so you
should unset `LD_LIBRARY_PATH` before doing that or use a different shell.

```sh
git push
OpenSSL version mismatch. Built against 30000080, you have 30200000
...
```

With all that setup as above the command line gets simpler:

```sh
./src/curl https://defo.ie/ech-check.php
...
SSL_ECH_STATUS: success <img src="greentick-small.png" alt="good" /> <br/>
...
```

The `--ech true` option is opportunistic, so tries to do ECH but does not fail if
the client for example cannot find any ECHConfig values. The `--ech hard`
option hard-fails if there is no ECHConfig found in DNS, so for now, that is not
a good option to set as a default. Once ECH has really been attempted by
the client, if decryption on the server side fails, then curl fails.

## Code changes for ECH support when using DoH

Code changes are `#ifdef` protected via `USE_ECH` or `USE_HTTPSRR`:

- `USE_HTTPSRR` is used for HTTPS RR retrieval code that could be generically
  used should non-ECH uses for HTTPS RRs be identified, e.g. use of ALPN values
  or IP address hints.

- `USE_ECH` protects ECH specific code.

There are various obvious code blocks for handling the new command line
arguments which are not described here, but should be fairly clear.

As shown in the `configure` usage above, there are `configure.ac` changes
that allow separately dis/enabling `USE_HTTPSRR` and `USE_ECH`. If `USE_ECH`
is enabled, then `USE_HTTPSRR` is forced. In both cases `CURL_DISABLE_DOH`
must not be enabled. (There may be some configuration conflicts available for the
determined :-)

The main functional change, as you would expect, is in `lib/vtls/openssl.c`
where an ECHConfig, if available from command line or DNS cache, is fed into
the OpenSSL library via the new APIs implemented in our OpenSSL fork for that
purpose. This code also implements the opportunistic (`--ech true`) or hard-fail
(`--ech hard`) logic.

Other than that, the main additions are in `lib/doh.c`
where we reuse `dohprobe()` to retrieve an HTTPS RR value for the target
domain. If such a value is found, that is stored using a new `doh_store_https()`
function in a new field in the `dohentry` structure.

The qname for the DoH query is modified if the port number is not 443, as
defined in the SVCB specification.

When the DoH process has worked, `Curl_doh_take_result()` now also returns
the relevant HTTPS RR value data in the `Curl_dns_entry` structure.
That is later accessed when the TLS session is being established, if ECH is
enabled (from `lib/vtls/openssl.c` as described above).

## Limitations

Things that need fixing, but that can probably be ignored for the
moment:

- We could easily add code to make use of an `alpn=` value found in an HTTPS
  RR, passing that on to OpenSSL for use as the "inner" ALPN value, but have
  yet to do that.

Current limitations (more interesting than the above):

- Only the first HTTPS RR value retrieved is actually processed as described
  above, that could be extended in future, though picking the "right" HTTPS RR
  could be non-trivial if multiple RRs are published - matching IP address
  hints versus A/AAAA values might be a good basis for that. Last I checked
  though, browsers supporting ECH did not handle multiple HTTPS RRs well, though
  that needs re-checking as it has been a while.

- It is unclear how one should handle any IP address hints found in an HTTPS RR.
  It may be that a bit of consideration of how "multi-CDN" deployments might
  emerge would provide good answers there, but for now, it is not clear how best
  curl might handle those values when present in the DNS.

- The SVCB/HTTPS RR specification supports a new "CNAME at apex" indirection
  ("aliasMode") - the current code takes no account of that at all. One could
  envisage implementing the equivalent of following CNAMEs in such cases, but
  it is not clear if that'd be a good plan. (As of now, chrome browsers do not
  seem to have any support for that "aliasMode" and we have not checked Firefox
  for that recently.)

- We have not investigated what related changes or additions might be needed
  for applications using libcurl, as opposed to use of curl as a command line
  tool.

- We have not yet implemented tests as part of the usual curl test harness as
  doing so would seem to require re-implementing an ECH-enabled server as part
  of the curl test harness. For now, we have a `./tests/ech_test.sh` script
  that attempts ECH with various test servers and with many combinations of the
  allowed command line options. While that is a useful test and has find
  issues, it is not comprehensive and we are not (as yet) sure what would be
  the right level of coverage. When running that script you should not have a
  `$HOME/.curlrc` file that affects ECH or some of the negative tests could
  produce spurious failures.

## Building with cmake

To build with cmake, assuming our ECH-enabled OpenSSL is as before:

```sh
cd $HOME/code
git clone --depth 1 https://github.com/curl/curl
cd curl
mkdir build
cd build
cmake -DOPENSSL_ROOT_DIR=$HOME/code/openssl -DUSE_ECH=1 ..
...
make
...
[100%] Built target curl
```

The binary produced by the cmake build does not need any ECH-specific
`LD_LIBRARY_PATH` setting.

## BoringSSL build

BoringSSL is also supported by curl and also supports ECH, so to build
with that, instead of our ECH-enabled OpenSSL:

```sh
cd $HOME/code
git clone --depth 1 https://boringssl.googlesource.com/boringssl
cd boringssl
cmake -DCMAKE_INSTALL_PREFIX:PATH=$HOME/code/boringssl/inst -DBUILD_SHARED_LIBS=1
make
...
make install
```

Then:

```sh
cd $HOME/code
git clone --depth 1 https://github.com/curl/curl
cd curl
autoreconf -fi
LDFLAGS="-Wl,-rpath,$HOME/code/boringssl/inst/lib" ./configure --with-ssl=$HOME/code/boringssl/inst --enable-ech
...lots of output...
WARNING: ECH HTTPSRR enabled but marked EXPERIMENTAL. Use with caution.
make
```

The AWS-LC/BoringSSL APIs are fairly similar to those in our ECH-enabled
OpenSSL fork, so code changes are also in `lib/vtls/openssl.c`, protected
via `#ifdef OPENSSL_IS_BORINGSSL` and are mostly obvious API variations.

The AWS-LC/BoringSSL APIs however do not support the `--ech pn:` command
line variant as of now.

## wolfSSL build

wolfSSL also supports ECH and can be used by curl, so here's how:

```sh
cd $HOME/code
git clone --depth 1 https://github.com/wolfSSL/wolfssl
cd wolfssl
./autogen.sh
./configure --prefix=$HOME/code/wolfssl/inst --enable-ech --enable-debug --enable-opensslextra
make
make install
```

The install prefix (`inst`) in the above causes wolfSSL to be installed there
and we seem to need that for the curl configure command to work out. The
`--enable-opensslextra` turns out (after much faffing about;-) to be
important or else we get build problems with curl below.

```sh
cd $HOME/code
git clone --depth 1 https://github.com/curl/curl
cd curl
autoreconf -fi
./configure --with-wolfssl=$HOME/code/wolfssl/inst --enable-ech
make
```

There are some known issues with the ECH implementation in wolfSSL:

- The main issue is that the client currently handles HelloRetryRequest
  incorrectly. [HRR issue](https://github.com/wolfSSL/wolfssl/issues/6802).)
  The HRR issue means that the client does not work for
  [this ECH test web site](https://tls-ech.dev/) and any other similarly
  configured sites.
- There is also an issue related to so-called middlebox compatibility mode.
  [middlebox compatibility issue](https://github.com/wolfSSL/wolfssl/issues/6774)

### Code changes to support wolfSSL

There are what seem like oddball differences:

- The DoH URL in`$HOME/.curlrc` can use `1.1.1.1` for OpenSSL but has to be
  `one.one.one.one` for wolfSSL. The latter works for both, so OK, we us that.
- There seems to be some difference in CA databases too - the wolfSSL version
  does not like `defo.ie`, whereas the system and OpenSSL ones do. We can
  ignore that for our purposes via `--insecure`/`-k` but would need to fix
  for a real setup. (Browsers do like those certificates though.)

Then there are some functional code changes:

- tweak to `configure.ac` to check if wolfSSL has ECH or not
- added code to `lib/vtls/wolfssl.c` mirroring what's done in the
  OpenSSL equivalent above.
- wolfSSL does not support `--ech false` or the `--ech pn:` command line
  argument.

The lack of support for `--ech false` is because wolfSSL has decided to
always at least GREASE if built to support ECH. In other words, GREASE is
a compile time choice for wolfSSL, but a runtime choice for OpenSSL or
AWS-LC/BoringSSL. (Both are reasonable.)

## Additional notes

### Supporting ECH without DoH

All of the above only applies if DoH is being used. There should be a use-case
for ECH when DoH is not used by curl - if a system stub resolver supports DoT
or DoH, then, considering only ECH and the network threat model, it would make
sense for curl to support ECH without curl itself using DoH. The author for
example uses a combination of stubby+unbound as the system resolver listening
on localhost:53, so would fit this use-case. That said, it is unclear if this
is a niche that is worth trying to address. (The author is happy to let curl
use DoH to talk to the same public recursive that stubby might use:-)

Assuming for the moment this is a use-case we would like to support, then if
DoH is not being used by curl, it is not clear at this time how to provide
support for ECH. One option would seem to be to extend the `c-ares` library
to support HTTPS RRs, but in that case it is not now clear whether such
changes would be attractive to the `c-ares` maintainers, nor whether the
"tag=value" extensibility inherent in the HTTPS/SVCB specification is a good
match for the `c-ares` approach of defining structures specific to decoded
answers for each supported RRtype. We are also not sure how many downstream
curl deployments actually make use of the `c-ares` library, which would
affect the utility of such changes. Another option might be to consider using
some other generic DNS library that does support HTTPS RRs, but it is unclear
if such a library could or would be used by all or almost all curl builds and
downstream releases of curl.

Our current conclusion is that doing the above is likely best left until we
have some experience with the "using DoH" approach, so we are going to punt on
this for now.

### Localhost testing

It can be useful to be able to run against a localhost OpenSSL `s_server`
for testing. We have published instructions for such
[localhost tests](https://github.com/defo-project/ech-dev-utils/blob/main/howtos/localhost-tests.md)
in another repository. Once you have that set up, you can start a server
and then run curl against that:

```sh
cd $HOME/code/ech-dev-utils
./scripts/echsvr.sh -d
...
```

The `echsvr.sh` script supports many ECH-related options. Use `echsvr.sh -h`
for details.

In another window:

```sh
cd $HOME/code/curl/
./src/curl -vvv --insecure --connect-to foo.example.com:8443:localhost:8443 \
  --ech ecl:AD7+DQA6uwAgACBix2B78sX+EQhEbxMspDOc8Z3xVS5aQpYP0Cxpc2AWPAAEAAEAAQALZXhhbXBsZS5jb20AAA==
```

### Automated use of `retry_configs` not supported so far...

As of now we have not added support for using `retry_config` handling in the
application - for a command line tool, one can use `dig` (or `kdig`) to
get the HTTPS RR and pass the ECHConfigList from that on the command line, if
needed, or one can access the value from command line output in verbose more
and then reuse that in another invocation.

Both our OpenSSL fork and AWS-LC/BoringSSL have APIs for both controlling GREASE
and accessing and logging `retry_configs`, it seems wolfSSL has neither.

### Testing ECH

We have yet to add a robust test setup for ECH as that requires an ECH-enabled
test server.

We have added two basic tests though, aiming to ensure that the client sends a
GREASE or real ECH extension when requested, and reacts correctly to the
failure of ECH in the latter case. (Given that `stunnel` has no ECH support.)

As with other similar tests, those tests require the `stunnel` tool be
installed. On Ubuntu `sudo apt install stunnel4` achieves that.

The test cases are:

- data/test4000: GREASE ECH, expected result: connection succeeds
- data/test4001: real ECH, connection fails with error 101 (ECH required)
<!--
Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.

SPDX-License-Identifier: curl
-->

# Experimental

Some features and functionality in curl and libcurl are considered
**EXPERIMENTAL**.

Experimental support in curl means:

1. Experimental features are provided to allow users to try them out and
   provide feedback on functionality and API etc before they ship and get
   "carved in stone".
2. You must enable the feature when invoking configure as otherwise curl is
   not built with the feature present.
3. We strongly advise against using this feature in production.
4. **We reserve the right to change behavior** of the feature without sticking
   to our API/ABI rules as we do for regular features, as long as it is marked
   experimental.
5. Experimental features are clearly marked so in documentation. Beware.
6. Vulnerabilities in experimental features are not considered security
   problems; please report them as regular bugs/feedback instead.

## Graduation

1. Each experimental feature should have a set of documented requirements of
   what is needed for that feature to graduate. Graduation means being removed
   from the list of experiments.
2. An experiment should NOT graduate if it needs test cases to be disabled,
   unless they are for minor features that are clearly documented as not
   provided by the experiment and then the disabling should be managed inside
   each affected test case.

## The quiche QUIC and HTTP/3 backend

Graduation requirements:

- The library should be considered out-of-beta

- a reasonable expectation of a stable API going forward

- HTTP/3 with the given build should perform without risking busy-loops

## HTTP/3 proxy and CONNECT-UDP support

Support for HTTP/3 proxy and CONNECT-UDP tunneling is experimental and
requires an explicit build-time opt-in (`--enable-proxy-http3` for
autotools, `-DUSE_PROXY_HTTP3=ON` for CMake).

Graduation requirements:

- implementation stability over time with no known severe regressions

## The Rustls TLS backend

Graduation requirements:

- a reasonable expectation of a stable API going forward.

## ECH

Use of the HTTPS resource record and Encrypted Client Hello (ECH) when using
DoH

Graduation requirements:

- ECH support exists in at least one widely used TLS library apart from
  BoringSSL and wolfSSL.

- feedback from users saying that ECH works for their use cases

- it has been given time to mature, so no earlier than April 2025 (twelve
  months after being added here)

## SSL session import/export

Import/Export of SSL sessions tickets in libcurl and curl command line
option '--ssl-session <filename>' for faster TLS handshakes and use
of TLSv1.3/QUIC Early Data (0-RTT).

Graduation requirements:

- the implementation is considered safe

- feedback from users saying that session export works for their use cases

## HTTPS RR

HTTPS records support is a requirement for ECH but is provided as a
stand-alone feature that is itself considered EXPERIMENTAL.

Graduation requirements:

- HTTPS records work for DoH, c-ares and the threaded resolver

- HTTPS records can control ALPN and port number, at least

- There are options to control HTTPS use

## HTTP Message Signatures (RFC 9421)

Sign outgoing HTTP requests according to RFC 9421 using the
`--httpsig-algo`, `--httpsig-key`, `--httpsig-keyid` and
`--httpsig-headers` command line options, or the corresponding
`CURLOPT_HTTPSIG_*` libcurl options. Built only when configured with
`--enable-httpsig`.

Graduation requirements:

- the option set (names, arguments, defaults) is settled

- interoperability has been verified against at least two independent
  RFC 9421 implementations

- no test cases are disabled for the feature

- feedback from users saying the API works for their use cases

## Apple fast UDP

There are undocumented system calls available in Apple operating systems that
when used allow for faster sending and receiving of UDP messages.

The undocumented and thus unsupported-by-Apple nature of these functions
brings a risk that they are removed in a future OS update, or perhaps worse:
marginally modified to instead cause subtle and hard-to-spot bugs.

Graduation requirements:

- testimonials from users that these work reliably

- measurements that show they make a measurable performance impact

- an easy way to (re-)build curl to not use these functions
<!--
Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.

SPDX-License-Identifier: curl
-->

# Frequently Asked Questions

# Philosophy

## What is curl?

curl is the name of the project. The name is a play on *Client for URLs*,
originally with URL spelled in uppercase to make it obvious it deals with
URLs. The fact it can also be read as *see URL* also helped, it works as an
abbreviation for *Client URL Request Library* or why not the recursive
version: *curl URL Request Library*.

The curl project produces two products:

### libcurl

A client-side URL transfer library, supporting DICT, FILE, FTP, FTPS, GOPHER,
GOPHERS, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, MQTT, MQTTS, POP3, POP3S,
RTSP, SCP, SFTP, SMB, SMBS, SMTP, SMTPS, TELNET, TFTP, WS and WSS.

libcurl supports HTTPS certificates, HTTP POST, HTTP PUT, FTP uploading,
Kerberos, SPNEGO, HTTP form based upload, proxies, cookies, user+password
authentication, file transfer resume, http proxy tunneling and more.

libcurl is highly portable, it builds and works identically on numerous
platforms. The [internals document](https://curl.se/docs/install.html#Ports)
lists more than 110 operating systems and 28 CPU architectures on which curl
has been reported to run.

libcurl is free, thread-safe, IPv6 compatible, feature-rich, well supported
and fast.

### curl

A command line tool for getting or sending data using URL syntax.

Since curl uses libcurl, curl supports the same wide range of common Internet
protocols that libcurl does.

We pronounce curl with an initial k sound. It rhymes with words like girl and
earl. [This is a short WAV
file](https://media.merriam-webster.com/soundc11/c/curl0001.wav) to help you.

There are numerous sub-projects and related projects that also use the word
curl in the project names in various combinations, but you should take notice
that this FAQ is directed at the command-line tool named curl (and libcurl the
library), and may therefore not be valid for other curl-related projects.
(There is however a small section for the PHP/CURL in this FAQ.)

## What is libcurl?

libcurl is a reliable and portable library for doing Internet data transfers
using one or more of its supported Internet protocols.

You can use libcurl freely in your application, be it open source, commercial
or closed-source.

libcurl is most probably the most portable, most powerful and most often used
C-based multi-platform file transfer library on this planet - be it open
source or commercial.

## What is curl not?

curl is not a Wget clone. That is a common misconception. Never, during curl's
development, have we intended curl to replace Wget or compete on its market.
curl is targeted at single-shot file transfers.

curl is not a website mirroring program. If you want to use curl to mirror
something: fine, go ahead and write a script that wraps around curl or use
libcurl to make it reality.

curl is not an FTP site mirroring program. Sure, get and send FTP with curl
but if you want systematic and sequential behavior you should write a script
(or write a new program that interfaces libcurl) and do it.

curl is not a PHP tool, even though it works perfectly well when used from or
with PHP (when using the PHP/CURL module).

curl is not a program for a single operating system. curl exists, compiles,
builds and runs under a wide range of operating systems, including all modern
Unixes (and a bunch of older ones too), Windows, Amiga, OS/2, macOS, QNX etc.

## When would you make curl do ... ?

We love suggestions of what to change in order to make curl and libcurl
better. We do however believe in a few rules when it comes to the future of
curl:

curl the command line tool is to remain a non-graphical command line tool. If
you want GUIs or fancy scripting capabilities, you should look for another
tool that uses libcurl.

We do not add things to curl that other small and available tools already do
well at the side. curl's output can be piped into another program or
redirected to another file for the next program to interpret.

We focus on protocol related issues and improvements. If you want to do more
with the supported protocols than curl currently does, chances are good we
would agree. If you want to add more protocols, we may agree.

If you want someone else to do all the work while you wait for us to implement
it for you, that is not a friendly attitude. We spend a considerable time
already on maintaining and developing curl. In order to get more out of us,
you should consider trading in some of your time and effort in return. Go to
the [GitHub repository](https://github.com/curl/curl), fork the project,
and create pull requests with your proposed changes.

If you write the code, chances are better that it gets into curl faster.

## Who makes curl?

curl and libcurl are not made by any single individual. Daniel Stenberg is
project leader and main developer, but other persons' submissions are
important and crucial. Anyone can contribute and post their changes and
improvements and have them inserted in the main sources (of course on the
condition that developers agree that the fixes are good).

The full list of all contributors is found in the
[docs/THANKS](https://curl.se/docs/thanks.html) file.

curl is developed by a community, with Daniel at the wheel.

## What do you get for making curl?

Project curl is entirely free and open. We do this voluntarily, mostly in our
spare time. Companies may pay individual developers to work on curl. This is
not controlled by nor supervised in any way by the curl project.

We get help from companies. Haxx provides website, bandwidth, mailing lists
etc, GitHub hosts [the primary git repository](https://github.com/curl/curl)
and other services like the bug tracker. Also again, some companies have
sponsored certain parts of the development in the past and I hope some
continue to do so in the future.

If you want to [support our project](https://curl.se/sponsors.html), consider
a donation or a banner-program or even better: by helping us with coding,
documenting or testing etc.

## What about CURL from curl.com?

During the summer of 2001, curl.com was busy advertising their client-side
programming language for the web, named CURL.

We are in no way associated with curl.com or their CURL programming language.

Our project name curl has been in effective use since 1998. We were not the
first computer related project to use the name *curl* and do not claim any
rights to the name.

We recognize that we are living in parallel with curl.com and wish them
every success.

## I have a problem, who do I mail?

Please do not mail any single individual unless you really need to. Keep
curl-related questions on a suitable mailing list. All available mailing lists
are listed [online](https://curl.se/mail/).

Keeping curl-related questions and discussions on mailing lists allows others
to join in and help, to share their ideas, to contribute their suggestions and
to spread their wisdom. Keeping discussions on public mailing lists also
allows for others to learn from this (both current and future users thanks to
the web based archives of the mailing lists), thus saving us from having to
repeat ourselves even more. Thanks for respecting this.

If you have found or suspect a security problem in curl or libcurl,
[submit all the details to us](https://curl.se/dev/vuln-disclosure.html). We
keep the issue private while we investigate, confirm it, work and validate a
fix and agree on a time schedule for publication etc. That way we produce a
fix in a timely manner before the flaw is announced to the world, reducing the
impact the problem risks having on existing users.

Security issues can also be taken to the curl security team by emailing
security at curl.se (closed list of receivers, mails are not disclosed).

## Where do I buy commercial support for curl?

curl is fully open source. It means you can hire any skilled engineer to fix
your curl-related problems.

We list [available alternatives](https://curl.se/support.html).

## How many are using curl?

It is impossible to tell.

We do not know how many users that knowingly have installed and use curl.

We do not know how many users that use curl without knowing that they are in
fact using it.

We do not know how many users that downloaded or installed curl and then never
use it.

In 2025, we estimate that curl runs in roughly thirty billion installations
world wide.

## Why do you not update ca-bundle.crt

In the curl project we have decided not to attempt to keep this file updated
(or even present) since deciding what to add to a CA cert bundle is an
undertaking we have not been ready to accept, and the one we can get from
Mozilla is perfectly fine so there is no need to duplicate that work.

Today, with many services performed over HTTPS, every operating system should
come with a default CA cert bundle that can be deemed somewhat trustworthy and
that collection (if reasonably updated) should be deemed to be a lot better
than a private curl version.

If you want the most recent collection of CA certs that Mozilla Firefox uses,
we recommend using our online [CA certificate
service](https://curl.se/docs/caextract.html) setup for this purpose.

## I have a problem, who can I chat with?

There is a bunch of friendly people hanging out in the #curl channel on the
IRC network libera.chat. If you are polite and nice, chances are good that you
can get -- or provide -- help instantly.

## curl's ECCN number?

The US government restricts exports of software that contains or uses
cryptography. When doing so, the Export Control Classification Number (ECCN)
is used to identify the level of export control etc.

Apache Software Foundation has [a good explanation of
ECCN](https://www.apache.org/dev/crypto.html).

We believe curl's number might be ECCN 5D002, another possibility is 5D992. It
seems necessary to write them (the authority that administers ECCN numbers),
asking to confirm.

Comprehensible explanations of the meaning of such numbers and how to obtain
them (resp.) are [here](https://www.bis.gov/licensing/classify-your-item)
and [here](https://www.bis.gov/licensing/classify-your-item/publicly-available-classification-information).

An incomprehensible description of the two numbers above is available on
[bis.doc.gov](https://www.bis.doc.gov/index.php/documents/new-encryption/1653-ccl5-pt2-3)

## How do I submit my patch?

We strongly encourage you to submit changes and improvements directly as [pull
requests on GitHub](https://github.com/curl/curl/pulls).

If you cannot or choose not to engage with GitHub, send your patch
to the curl-library mailing list. We are many subscribers there and there are
lots of people who can review patches, comment on them and receive them
properly.

Many more details are found in the
[contribute](https://curl.se/dev/contribute.html) and
[internals](https://curl.se/dev/internals.html)
documents.

## How do I port libcurl to my OS?

Here's a rough step-by-step:

1. copy a suitable `lib/config-*.h` file as a start to `lib/config-[youros].h`
2. edit `lib/config-[youros].h` to match your OS and setup
3. edit `lib/curl_setup.h` to include `config-[youros].h` when your OS is
   detected by the preprocessor, in the style others already exist
4. compile `lib/*.c` and make them into a library

# Install

## configure fails when using static libraries

You may find that configure fails to properly detect the entire dependency
chain of libraries when you provide static versions of the libraries that
configure checks for.

The reason why static libraries are much harder to deal with is that for them
we do not get any help but the script itself must know or check what more
libraries that are needed (with shared libraries, that dependency chain is
handled automatically). This is an error-prone process and one that also tends
to vary over time depending on the release versions of the involved components
and may also differ between operating systems.

For that reason, configure does few attempts to actually figure this out and
you are instead encouraged to set `LIBS` and `LDFLAGS` accordingly when you invoke
configure, and point out the needed libraries and set the necessary flags
yourself.

## Does curl work with other SSL libraries?

curl has been written to use a generic SSL function layer internally, and
that SSL functionality can then be provided by one out of many different SSL
backends.

curl can be built to use one of the following SSL alternatives: AWS-LC,
BoringSSL, GnuTLS, LibreSSL, OpenSSL, mbedTLS, Rustls, Schannel (native
Windows), or wolfSSL. They all have their pros and cons, and we maintain
[a TLS library comparison](https://curl.se/docs/ssl-compared.html).

## How do I upgrade curl.exe in Windows?

The curl tool that is shipped as an integrated component of Windows 10 and
Windows 11 is managed by Microsoft. If you were to delete the file or replace
it with a newer version downloaded from [the curl
website](https://curl.se/windows/), then Windows Update ceases to work on
your system.

There is no way to independently force an upgrade of the curl.exe that is part
of Windows other than through the regular Windows update process. There is
also nothing the curl project itself can do about this, since this is managed
and controlled entirely by Microsoft as owners of the operating system.

You can always download and install [the latest version of curl for
Windows](https://curl.se/windows/) into a separate location.

## Does curl support SOCKS (RFC 1928) ?

Yes, SOCKS 4 and 5 are supported.

# Usage

## curl: (1) SSL is disabled, https: not supported

If you get this output when trying to get anything from an HTTPS server, it
means that the instance of curl/libcurl that you are using was built without
support for this protocol.

This could have happened if the configure script that was run at build time
could not find all libs and include files curl requires for SSL to work. If
the configure script fails to find them, curl is built without SSL
support.

To get HTTPS support into a curl that was previously built but that reports
that HTTPS is not supported, you should dig through the document and logs and
check out why the configure script does not find the SSL libs and/or include
files.

## How do I tell curl to resume a transfer?

curl supports resumed transfers both ways on both FTP and HTTP. Try the `-C`
option.

## Why does my posting using -F not work?

You cannot arbitrarily use `-F` or `-d`, the choice between `-F` or `-d`
depends on the HTTP operation you need curl to do and what the web server that
receives your post expects.

If the form you are trying to submit uses the type 'multipart/form-data',
then and only then you must use the -F type. In all the most common cases,
you should use `-d` which then causes a posting with the type
`application/x-www-form-urlencoded`.

This is described in some detail in the
[Manual](https://curl.se/docs/tutorial.html) and [The Art Of HTTP
Scripting](https://curl.se/docs/httpscripting.html) documents, and if you do
not understand it the first time, read it again before you post questions
about this to the mailing list. Also, try reading through the mailing list
archives for old postings and questions regarding this.

## How do I tell curl to run custom FTP commands?

You can tell curl to perform optional commands both before and/or after a file
transfer. Study the `-Q`/`--quote` option.

Since curl is used for file transfers, you do not normally use curl to perform
FTP commands without transferring anything. Therefore you must always specify
a URL to transfer to/from even when doing custom FTP commands, or use `-I`
which implies the *no body* option sent to libcurl.

## How can I disable the Accept: header?

You can change this and all internally generated headers by adding a
replacement with the `-H`/`--header` option. By adding a header with empty
contents you safely disable that one. Use `-H Accept:` to disable that
specific header.

## Does curl support ASP, XML, XHTML or HTML version Y?

To curl, all contents are alike. It does not matter how the page was
generated. It may be ASP, PHP, Perl, shell-script, SSI or plain HTML
files. There is no difference to curl and it does not even know what kind of
language that generated the page.

See also the separate question about JavaScript.

## Can I use curl to delete/rename a file through FTP?

Yes. You specify custom FTP commands with `-Q`/`--quote`.

One example would be to delete a file after you have downloaded it:

    curl -O ftp://example.com/coolfile -Q '-DELE coolfile'

or rename a file after upload:

    curl -T infile ftp://example.com/dir/ -Q "-RNFR infile" -Q "-RNTO newname"

## How do I tell curl to follow HTTP redirects?

curl does not follow so-called redirects by default. The `Location:` header that
informs the client about this is only interpreted if you are using the
`-L`/`--location` option. As in:

    curl -L https://example.com

Not all redirects are HTTP ones. See [Redirects work in browser but not with
curl](#redirects-work-in-browser-but-not-with-curl)

## How do I use curl in my favorite programming language?

Many programming languages have interfaces and bindings that allow you to use
curl without having to use the command line tool. If you are fluent in such a
language, you may prefer to use one of these interfaces instead.

Find out more about which languages that support curl directly, and how to
install and use them, in the [libcurl section of the curl
website](https://curl.se/libcurl/).

All the various bindings to libcurl are made by other projects and people,
outside of the curl project. The curl project itself only produces libcurl
with its plain C API. If you do not find anywhere else to ask you can ask
about bindings on the curl-library list too, but be prepared that people on
that list may not know anything about bindings.

In December 2025 there were around **60** different [interfaces
available](https://curl.se/libcurl/bindings.html) for almost any language you
can imagine.

## What about SOAP, WebDAV, XML-RPC or similar protocols over HTTP?

curl adheres to the HTTP spec, which means you can play with *any* protocol
that is built on top of HTTP. Protocols such as SOAP, WebDAV and XML-RPC are
all such ones. You can use `-X` to set custom requests and -H to set custom
headers (or replace internally generated ones).

Using libcurl of course also works and you would use the proper library
options to do the same.

## How do I POST with a different Content-Type?

You can always replace the internally generated headers with `-H`/`--header`.
To make a simple HTTP POST with `text/xml` as content-type, do something like:

    curl -d "datatopost" -H "Content-Type: text/xml" [URL]

## Why do FTP-specific features over HTTP proxy fail?

Because when you use an HTTP proxy, the protocol spoken on the network is
HTTP, even if you specify an FTP URL. This effectively means that you normally
cannot use FTP-specific features such as FTP upload and FTP quote etc.

There is one exception to this rule, and that is if you can *tunnel through*
the given HTTP proxy. Proxy tunneling is enabled with a special option (`-p`)
and is generally not available as proxy admins usually disable tunneling to
ports other than 443 (which is used for HTTPS access through proxies).

## Why do my single/double quotes fail?

To specify a command line option that includes spaces, you might need to put
the entire option within quotes. Like in:

    curl -d " with spaces " example.com

or perhaps

    curl -d ' with spaces ' example.com

Exactly what kind of quotes and how to do this is entirely up to the shell or
command line interpreter that you are using. For most Unix shells, you can
more or less pick either single (`'`) or double (`"`) quotes. For Windows/DOS
command prompts you must use double (") quotes, and if the option string
contains inner double quotes you can escape them with a backslash.

For Windows PowerShell the arguments are not always passed on as expected
because curl is not a PowerShell script. You may or may not be able to use
single quotes. To escape inner double quotes seems to require a
backslash-backtick escape sequence and the outer quotes as double quotes.

Please study the documentation for your particular environment. Examples in
the curl docs use a mix of both of these as shown above. You must adjust them
to work in your environment.

Remember that curl works and runs on more operating systems than most single
individuals have ever tried.

## Does curl support JavaScript or PAC (automated proxy config)?

Many webpages do stuff using embedded JavaScript. curl and libcurl have
no built-in support for that, so it is treated like any other contents.

`.pac` files are a Netscape invention and are sometimes used by organizations
to allow them to differentiate which proxies to use. The `.pac` contents is a
JavaScript program that gets invoked by the browser and that returns the name
of the proxy to connect to. Since curl does not support JavaScript, it cannot
support .pac proxy configuration either.

Some workarounds usually suggested to overcome this JavaScript dependency:

Depending on the JavaScript complexity, write up a script that translates it
to another language and execute that.

Read the JavaScript code and rewrite the same logic in another language.

Implement a JavaScript interpreter, people have successfully used the
Mozilla JavaScript engine in the past.

Ask your admins to stop this, for a static proxy setup or similar.

## Can I do recursive fetches with curl?

No. curl itself has no code that performs recursive operations, such as those
performed by Wget and similar tools.

There exists curl using scripts with that functionality, and you can write
programs based on libcurl to do it, but the command line tool curl itself
cannot.

## What certificates do I need when I use SSL?

There are three different kinds of certificates to keep track of when we talk
about using SSL-based protocols (HTTPS or FTPS) using curl or libcurl.

### Client certificate

The server you communicate with may require that you can provide this in
order to prove that you actually are who you claim to be. If the server
does not require this, you do not need a client certificate.

A client certificate is always used together with a private key, and the
private key has a passphrase that protects it.

### Server certificate

The server you communicate with has a server certificate. You can and should
verify this certificate to make sure that you are truly talking to the real
server and not a server impersonating it.

Servers often also provide an intermediate certificate. It acts as a bridge
between a website's SSL certificate and a Certificate Authority's (CA) root
certificate, creating a "chain of trust".

### Certificate Authority Certificate ("CA cert")

You often have several CA certs in a CA cert bundle that can be used to verify
a server certificate that was signed by one of the authorities in the bundle.
curl does not come with a CA cert bundle but most curl installs provide one.
You can also override the default.

Server certificate verification is enabled by default in curl and libcurl.
Server certificates that are *self-signed* or otherwise signed by a CA that
you do not have a CA cert for, cannot be verified. If the verification during
a connect fails, you are refused access. You then might have to explicitly
disable the verification to connect to the server.

## How do I list the root directory of an FTP server?

There are two ways. The way defined in the RFC is to use an encoded slash in
the first path part. List the `/tmp` directory like this:

    curl ftp://ftp.example.com/%2ftmp/

The second way is non-standard but more readable; start the path section of the
URL with a slash:

    curl ftp://ftp.example.com//tmp/

## Can I use curl to send a POST/PUT and not wait for a response?

No.

You can easily write your own program using libcurl to do such stunts.

## How do I get HTTP from a host using a specific IP address?

For example, you may be trying out a website installation that is not yet in
the DNS. Or you have a site using multiple IP addresses for a given host
name and you want to address a specific one out of the set.

Set a custom `Host:` header that identifies the server name you want to reach
but use the target IP address in the URL:

    curl --header "Host: www.example.com" https://somewhere.example/

You can also opt to add faked hostname entries to curl with the --resolve
option. That has the added benefit to make things like redirects also work
properly. The above operation would instead be done as:

    curl --resolve www.example.com:80:127.0.0.1 https://www.example.com/

## How to SFTP from my user's home directory?

Contrary to how FTP works, SFTP and SCP URLs specify the exact directory to
work with. It means that if you do not specify that you want the user's home
directory, you get the actual root directory.

To specify a file in your user's home directory, you need to use the correct
URL syntax which for SFTP might look similar to:

    curl -O -u user:password sftp://example.com/~/file.txt

and for SCP it is a different protocol prefix:

    curl -O -u user:password scp://example.com/~/file.txt

## Protocol xxx not supported or disabled in libcurl

When passing on a URL to curl to use, it may respond that the particular
protocol is not supported or disabled. The particular way this error message
is phrased is because curl does not make a distinction internally of whether a
particular protocol is not supported (i.e. never got any code added that knows
how to speak that protocol) or if it was explicitly disabled. curl can be
built to only support a given set of protocols, and the rest would then be
disabled or not supported.

Note that this error also occurs if you pass a wrongly spelled protocol part
as in `htpts://example.com` or as in the less evident case if you prefix
the protocol part with a space as in `" https://example.com/"`.

## curl `-X` gives me HTTP problems

In normal circumstances, `-X` should hardly ever be used.

By default you use curl without explicitly saying which request method to use
when the URL identifies an HTTP transfer. If you pass in a URL like `curl
https://example.com` it uses GET. If you use `-d` or `-F`, curl uses POST,
`-I` causes a HEAD and `-T` makes it a PUT.

If for whatever reason you are not happy with these default choices that curl
does for you, you can override those request methods by specifying `-X
[WHATEVER]`. This way you can for example send a DELETE by doing
`curl -X DELETE [URL]`.

It is thus pointless to do `curl -XGET [URL]` as GET would be used anyway. In
the same vein it is pointless to do `curl -X POST -d data [URL]`. You can make
a fun and somewhat rare request that sends a request-body in a GET request
with something like `curl -X GET -d data [URL]`.

Note that `-X` does not actually change curl's behavior as it only modifies
the actual string sent in the request, but that may of course trigger a
different set of events.

Accordingly, by using `-XPOST` on a command line that for example would follow
a 303 redirect, you effectively prevent curl from behaving correctly. Be aware.

# Running

## Why do I get problems when I use & or % in the URL?

In general Unix shells, the & symbol is treated specially and when used, it
runs the specified command in the background. To safely send the & as a part
of a URL, you should quote the entire URL by using single (`'`) or double
(`"`) quotes around it. Similar problems can also occur on some shells with
other characters, including ?*!$~(){}<>\|;`. When in doubt, quote the URL.

An example that would invoke a remote CGI that uses &-symbols could be:

    curl 'https://www.example.com/cgi-bin/query?text=yes&q=curl'

In Windows, the standard DOS shell treats the percent sign specially and you
need to use TWO percent signs for each single one you want to use in the URL.

If you want a literal percent sign to be part of the data you pass in a POST
using `-d`/`--data` you must encode it as `%25` (which then also needs the
percent sign doubled on Windows machines).

## How can I use {, }, [ or ] to specify multiple URLs?

Because those letters have a special meaning to the shell, to be used in a URL
specified to curl you must quote them.

An example that downloads two URLs (sequentially) would be:

    curl '{curl,www}.haxx.se'

To be able to use those characters as actual parts of the URL (without using
them for the curl URL *globbing* system), use the `-g`/`--globoff` option:

    curl -g 'www.example.com/weirdname[].html'

## Why do I get downloaded data even though the webpage does not exist?

curl asks remote servers for the page you specify. If the page does not exist
at the server, the HTTP protocol defines how the server should respond and
that means that headers and a page get returned. That is how HTTP works.

By using the `--fail` option you can tell curl explicitly to not get any data
if the HTTP return code does not say success.

## Why do I get return code XXX from an HTTP server?

RFC 2616 clearly explains the return codes. This is a short transcript. Go
read the RFC for exact details:

### 400 Bad Request

The request could not be understood by the server due to malformed
syntax. The client SHOULD NOT repeat the request without modifications.

### 401 Unauthorized

The request requires user authentication.

### 403 Forbidden

The server understood the request, but is refusing to fulfill it.
Authorization cannot help and the request SHOULD NOT be repeated.

### 404 Not Found

The server has not found anything matching the Request-URI. No indication is
given as to whether the condition is temporary or permanent.

### 405 Method Not Allowed

The method specified in the Request-Line is not allowed for the resource
identified by the Request-URI. The response MUST include an `Allow:` header
containing a list of valid methods for the requested resource.

### 301 Moved Permanently

If you get this return code and an HTML output similar to this:

    <H1>Moved Permanently</H1> The document has moved <A
    HREF="https://same_url_now_with_a_trailing_slash.example/">here</A>.

it might be because you requested a directory URL but without the trailing
slash. Try the same operation again _with_ the trailing URL, or use the
`-L`/`--location` option to follow the redirection.

## Can you tell me what error code 142 means?

All curl error codes are described at the end of the man page, in the section
called **EXIT CODES**.

Error codes that are larger than the highest documented error code means that
curl has exited due to a crash. This is a serious error, and we appreciate a
detailed bug report from you that describes how we could go ahead and repeat
this.

## How do I keep usernames and passwords secret in curl command lines?

This problem has two sides:

The first part is to avoid having clear-text passwords in the command line so
that they do not appear in *ps* outputs and similar. That is easily avoided by
using the `-K` option to tell curl to read parameters from a file or stdin to
which you can pass the secret info. curl itself also attempts to hide the given
password by blanking out the option - this does not work on all platforms.

To keep the passwords in your account secret from the rest of the world is
not a task that curl addresses. You could of course encrypt them somehow to
at least hide them from being read by human eyes, but that is not what
anyone would call security.

Also note that regular HTTP (using Basic authentication) and FTP passwords are
sent as cleartext across the network. All it takes for anyone to fetch them is
to listen on the network. Eavesdropping is easy. Use more secure
authentication methods (like Digest, Negotiate or even NTLM) or consider the
SSL-based alternatives HTTPS and FTPS.

## I found a bug

It is not a bug if the behavior is documented. Read the docs first. Especially
check out the KNOWN_BUGS file, it may be a documented bug.

If it is a problem with a binary you have downloaded or a package for your
particular platform, try contacting the person who built the package/archive
you have.

If there is a bug, read the BUGS document first. Then report it as described
in there.

## curl cannot authenticate to a server that requires NTLM?

NTLM support requires OpenSSL, GnuTLS, mbedTLS or Microsoft Windows libraries
at build-time to provide this functionality.

## My HTTP request using HEAD, PUT or DELETE does not work

Many web servers allow or demand that the administrator configures the server
properly for these requests to work on the web server.

Some servers seem to support HEAD only on certain kinds of URLs.

To fully grasp this, try the documentation for the particular server software
you are trying to interact with. This is not anything curl can do anything
about.

## Why do my HTTP range requests return the full document?

Because the range may not be supported by the server, or the server may choose
to ignore it and return the full document anyway.

## Why do I get "certificate verify failed" ?

When you invoke curl and get an error 60 error back it means that curl could
not verify that the server's certificate was good. curl verifies the
certificate using the CA cert bundle and verifying for which names the
certificate has been granted.

To completely disable the certificate verification, use `-k`. This does
however enable man-in-the-middle attacks and makes the transfer **insecure**.
We strongly advise against doing this for more than experiments.

If you get this failure with a CA cert bundle installed and used, the server's
certificate might not be signed by one of the certificate authorities in your
CA store. It might for example be self-signed. You then correct this problem
by obtaining a valid CA cert for the server. Or again, decrease the security
by disabling this check.

At times, you find that the verification works in your favorite browser but
fails in curl. When this happens, the reason is usually that the server sends
an incomplete cert chain. The server is mandated to send all *intermediate
certificates* but does not. This typically works with browsers anyway since
they A) cache such certs and B) supports AIA which downloads such missing
certificates on demand. This is a bad server configuration. A good way to
figure out if this is the case it to use [the SSL Labs
server](https://www.ssllabs.com/ssltest/) test and check the certificate
chain.

Details are also in [the SSL certificates
document](https://curl.se/docs/sslcerts.html).

## Why is curl -R on Windows one hour off?

Since curl 7.53.0 this issue should be fixed as long as curl was built with
any modern compiler that allows for a 64-bit curl_off_t type. For older
compilers or prior curl versions it may set a time that appears one hour off.
This happens due to a flaw in how Windows stores and uses file modification
times and it is not easily worked around. For more details
[read this](https://web.archive.org/web/20050715084352/codeproject.com/datetime/dstbugs.asp).

## Redirects work in browser but not with curl

curl supports HTTP redirects well (see a previous question above). Browsers
generally support at least two other ways to perform redirects that curl does
not:

Meta tags. You can write an HTML tag that causes the browser to redirect
to another given URL after a certain time.

JavaScript. You can write a JavaScript program embedded in an HTML page that
redirects the browser to another given URL.

There is no way to make curl follow these redirects. You must either manually
figure out what the page is set to do, or write a script that parses the
results and fetches the new URL.

## FTPS does not work

curl supports FTPS (sometimes known as FTP-SSL) both implicit and explicit
mode.

When a URL is used that starts with `ftps://`, curl assumes implicit SSL on
the control connection and therefore immediately connects and tries to speak
SSL. `ftps://` connections default to port 990.

To use explicit FTPS, you use an `ftp://` URL and the `--ssl-reqd` option (or
one of its related flavors). This is the most common method, and the one
mandated by RFC 4217. This kind of connection then of course uses the standard
FTP port 21 by default.

## My HTTP POST or PUT requests are slow

libcurl makes all POST and PUT requests (except for requests with a small
request body) use the `Expect: 100-continue` header. This header allows the
server to deny the operation early so that libcurl can bail out before having
to send any data. This is useful in authentication cases and others.

Many servers do not implement the `Expect:` stuff properly and if the server
does not respond (positively) within 1 second libcurl continues and sends
off the data anyway.

You can disable libcurl's use of the `Expect:` header the same way you disable
any header, using `-H` / `CURLOPT_HTTPHEADER`, or by forcing it to use HTTP
1.0.

## Non-functional connect timeouts

In most Windows setups having a timeout longer than 21 seconds makes no
difference, as it only sends 3 TCP SYN packets and no more. The second
packet sent three seconds after the first and the third six seconds after
the second. No more than three packets are sent, no matter how long the
timeout is set.

See Windows option `TcpMaxConnectRetransmissions` for more.

Also, even on non-Windows systems there may run a firewall or anti-virus
software or similar that accepts the connection but does not actually do
anything else. This makes (lib)curl to consider the connection connected
and thus the connect timeout does not trigger.

## `file://` URLs containing drive letters (Windows, NetWare)

When using curl to try to download a local file, one might use a URL in this
format:

    file://D:/blah.txt

you find that even if `D:\blah.txt` does exist, curl returns a 'file not
found' error.

According to [RFC 1738](https://datatracker.ietf.org/doc/html/rfc1738),
`file://` URLs must contain a host component, but it is ignored by most
implementations. In the above example, `D:` is treated as the host component,
and is taken away. Thus, curl tries to open `/blah.txt`. If your system is
installed to drive C:, that resolves to `C:\blah.txt`, and if that does
not exist you get the not found error.

To fix this problem, use `file://` URLs with *three* leading slashes:

    file:///D:/blah.txt

Alternatively, if it makes more sense, specify `localhost` as the host
component:

    file://localhost/D:/blah.txt

In either case, curl should now be looking for the correct file.

## Why does not curl return an error when the network cable is unplugged?

Unplugging a cable is not an error situation. The TCP/IP protocol stack was
designed to be fault tolerant, so even though there may be a physical break
somewhere the connection should not be affected, but possibly delayed.
Eventually, the physical break gets fixed or the data re-routed around
the physical problem through another path.

In such cases, the TCP/IP stack is responsible for detecting when the network
connection is irrevocably lost. Since with some protocols it is perfectly
legal for the client to wait indefinitely for data, the stack may never report
a problem, and even when it does, it can take up to 20 minutes for it to
detect an issue. The curl option `--keepalive-time` enables keep-alive support
in the TCP/IP stack which makes it periodically probe the connection to make
sure it is still available to send data. That should reliably detect any
TCP/IP network failure.

TCP keep alive does not detect the network going down before the TCP/IP
connection is established (e.g. during a DNS lookup) or using protocols that
do not use TCP. To handle those situations, curl offers a number of timeouts
on its own. `--speed-limit`/`--speed-time` aborts if the data transfer rate
falls too low, and `--connect-timeout` and `--max-time` can be used to put
an overall timeout on the connection phase or the entire transfer.

A libcurl-using application running in a known physical environment (e.g. an
embedded device with only a single network connection) may want to act
immediately if its lone network connection goes down. That can be achieved by
having the application monitor the network connection on its own using an
OS-specific mechanism, then signaling libcurl to abort.

## curl does not return error for HTTP non-200 responses

Correct. Unless you use `-f` (`--fail`) or `--fail-with-body`.

When doing HTTP transfers, curl performs exactly what you are asking it to
do and if successful it does not return an error. You can use curl to test
your web server's "file not found" page (that gets 404 back), you can use it
to check your authentication protected webpages (that gets a 401 back) and so
on.

The specific HTTP response code does not constitute a problem or error for
curl. It sends and delivers HTTP as you asked and if that worked,
everything is fine and dandy. The response code is generally providing more
higher level error information that curl does not care about. The error was
not in the HTTP transfer.

If you want your command line to treat error codes in the 400 and up range as
errors and thus return a non-zero value and possibly show an error message,
curl has a dedicated option for that: `-f` (`CURLOPT_FAILONERROR` in libcurl
speak).

You can also use the `-w` option and the variable `%{response_code}` to
extract the exact response code that was returned in the response.

# libcurl

## Is libcurl thread-safe?

Yes.

We have written the libcurl code specifically adjusted for multi-threaded
programs. libcurl uses thread-safe functions instead of non-safe ones if your
system has such. Note that you must never share the same handle in multiple
threads.

There may be some exceptions to thread-safety depending on how libcurl was
built. Please review [the guidelines for thread
safety](https://curl.se/libcurl/c/threadsafe.html) to learn more.

## How can I receive all data into a large memory chunk?

(See the [get in memory](https://curl.se/libcurl/c/getinmemory.html) example.)

You are in full control of the callback function that gets called every time
there is data received from the remote server. You can make that callback do
whatever you want. You do not have to write the received data to a file.

One solution to this problem could be to have a pointer to a struct that you
pass to the callback function. You set the pointer using the CURLOPT_WRITEDATA
option. Then that pointer is passed to the callback instead of a FILE *
to a file:

~~~c
/* store data this struct */
struct MemoryStruct {
  char *memory;
  size_t size;
};

/* imaginary callback function */
size_t
WriteMemoryCallback(void *ptr, size_t size, size_t nmemb, void *data)
{
  size_t realsize = size * nmemb;
  struct MemoryStruct *mem = (struct MemoryStruct *)data;

  mem->memory = realloc(mem->memory, mem->size + realsize + 1);
  if(mem->memory) {
    memcpy(&(mem->memory[mem->size]), ptr, realsize);
    mem->size += realsize;
    mem->memory[mem->size] = 0;
  }
  return realsize;
}
~~~

## How do I fetch multiple files with libcurl?

libcurl has excellent support for transferring multiple files. You should
repeatedly set new URLs with `curl_easy_setopt()` and then transfer it with
`curl_easy_perform()`. The handle you get from curl_easy_init() is not only
reusable, but you are even encouraged to reuse it if you can, as that
enables libcurl to use persistent connections.

## Does libcurl do Winsock initialization on Win32 systems?

Yes, if told to in the `curl_global_init()` call.

## Does CURLOPT_WRITEDATA and CURLOPT_READDATA work on Win32 ?

Yes, but you cannot open a FILE * and pass the pointer to a DLL and have that
DLL use the FILE * (as the DLL and the client application cannot access each
others' variable memory areas). If you set `CURLOPT_WRITEDATA` you must also use
`CURLOPT_WRITEFUNCTION` as well to set a function that writes the file, even if
all it does is write the data to the specified FILE *. Similarly, if you use
`CURLOPT_READDATA` you must also specify `CURLOPT_READFUNCTION`.

## What about Keep-Alive or persistent connections?

curl and libcurl have excellent support for persistent connections when
transferring several files from the same server. curl attempts to reuse
connections for all URLs specified on the same command line/config file, and
libcurl reuses connections for all transfers that are made using the same
libcurl handle.

When you use the easy interface the connection cache is kept within the easy
handle. If you instead use the multi interface, the connection cache is kept
within the multi handle and shared among all the easy handles that are used
within the same multi handle.

## Link errors when building libcurl on Windows

You need to make sure that your project, and all the libraries (both static
and dynamic) that it links against, are compiled/linked against the same run
time library.

This is determined by the `/MD`, `/ML`, `/MT` (and their corresponding `/M?d`)
options to the command line compiler. `/MD` (linking against `MSVCRT.dll`)
seems to be the most commonly used option.

When building an application that uses the static libcurl library, you must
add `-DCURL_STATICLIB` to your `CFLAGS`. Otherwise the linker looks for
dynamic import symbols. If you are using Visual Studio, you need to instead
add `CURL_STATICLIB` in the "Preprocessor Definitions" section.

If you get a linker error like `unknown symbol __imp__curl_easy_init ...` you
have linked against the wrong (static) library. If you want to use the
libcurl.dll and import lib, you do not need any extra `CFLAGS`, but use one of
the import libraries below. These are the libraries produced by the various
lib/Makefile.* files:

| Target         | static lib     | import lib for DLL |
|----------------|----------------|--------------------|
| MinGW          | `libcurl.a`    | `libcurldll.a`     |
| MSVC (release) | `libcurl.lib`  | `libcurl_imp.lib`  |
| MSVC (debug)   | `libcurld.lib` | `libcurld_imp.lib` |

## libcurl.so.X: open failed: No such file or directory

This is an error message you might get when you try to run a program linked
with a shared version of libcurl and your runtime linker (`ld.so`) could not
find the shared library named `libcurl.so.X`. (Where X is the number of the
current libcurl ABI, typically 3 or 4).

You need to make sure that `ld.so` finds `libcurl.so.X`. You can do that
multiple ways, and it differs somewhat between different operating systems.
They are usually:

* Add an option to the linker command line that specify the hard-coded path
  the runtime linker should check for the lib (usually `-R`)
* Set an environment variable (`LD_LIBRARY_PATH` for example) where `ld.so`
  should check for libs
* Adjust the system's config to check for libs in the directory where you have
  put the library (like Linux's `/etc/ld.so.conf`)

`man ld.so` and `man ld` tells you more details

## How does libcurl resolve hostnames?

libcurl supports a large number of name resolve functions. One of them is
picked at build-time and used unconditionally. Thus, if you want to change
name resolver function you must rebuild libcurl and tell it to use
a different function.

### The non-IPv6 resolver

The non-IPv6 resolver that can use one of four different hostname resolve
calls depending on what your system supports:

1. gethostbyname()
2. gethostbyname_r() with 3 arguments
3. gethostbyname_r() with 5 arguments
4. gethostbyname_r() with 6 arguments

### The IPv6 resolver

Uses getaddrinfo()

### The cares resolver

The c-ares based name resolver that uses the c-ares library for resolves.
Using this offers asynchronous name resolves.

## The threaded resolver

It uses the IPv6 or the non-IPv6 resolver solution in a temporary thread.

## How do I prevent libcurl from writing the response to stdout?

libcurl provides a default built-in write function that writes received data
to stdout. Set the `CURLOPT_WRITEFUNCTION` to receive the data, or possibly
set `CURLOPT_WRITEDATA` to a different FILE * handle.

## How do I make libcurl not receive the whole HTTP response?

You make the write callback (or progress callback) return an error and libcurl
then aborts the transfer.

## Can I make libcurl fake or hide my real IP address?

No. libcurl operates on a higher level. Besides, faking IP address would
imply sending IP packets with a made-up source address, and then you normally
get a problem with receiving the packet sent back as they would then not be
routed to you.

If you use a proxy to access remote sites, the sites do not see your local
IP address but instead the address of the proxy.

Also note that on many networks NATs or other IP-munging techniques are used
that makes you see and use a different IP address locally than what the remote
server is seeing you coming from. You may also consider using
[Tor](https://www.torproject.org/).

## How do I stop an ongoing transfer?

With the easy interface you make sure to return the correct error code from
one of the callbacks, but none of them are instant. There is no function you
can call from another thread or similar that stops it immediately.
Instead, you need to make sure that one of the callbacks you use returns an
appropriate value that stops the transfer. Suitable callbacks that you can
do this with include the progress callback, the read callback and the write
callback.

If you are using the multi interface, you can also stop a transfer by removing
the particular easy handle from the multi stack at any moment you think the
transfer is done or when you wish to abort the transfer.

## Using C++ non-static functions for callbacks?

libcurl is a C library, it does not know anything about C++ member functions.

You can overcome this limitation with relative ease using a static member
function that is passed a pointer to the class:

~~~c++
// f is the pointer to your object.
static size_t YourClass::func(char *buffer, size_t sz, size_t n, void *f)
{
  // Call non-static member function.
  static_cast<YourClass*>(f)->nonStaticFunction();
}

// This is how you pass pointer to the static function:
curl_easy_setopt(hcurl, CURLOPT_WRITEFUNCTION, YourClass::func);
curl_easy_setopt(hcurl, CURLOPT_WRITEDATA, this);
~~~

## How do I get an FTP directory listing?

If you end the FTP URL you request with a slash, libcurl provides you with
a directory listing of that given directory. You can also set
`CURLOPT_CUSTOMREQUEST` to alter what exact listing command libcurl would use
to list the files.

The follow-up question tends to be how is a program supposed to parse the
directory listing. How does it know what's a file and what's a directory and
what's a symlink etc. If the FTP server supports the `MLSD` command then it
returns data in a machine-readable format that can be parsed for type. The
types are specified by RFC 3659 section 7.5.1. If `MLSD` is not supported then
you have to work with what you are given. The `LIST` output format is entirely
at the server's own liking and the `NLST` output does not reveal any types and
in many cases does not even include all the directory entries. Also, both
`LIST` and `NLST` tend to hide Unix-style hidden files (those that start with
a dot) by default so you need to do `LIST -a` or similar to see them.

Example - List only directories. `ftp.funet.fi` supports `MLSD` and
`ftp.kernel.org` does not:

    curl -s ftp.funet.fi/pub/ -X MLSD | \
      perl -lne 'print if s/(?:^|;)type=dir;[^ ]+ (.+)$/$1/'

    curl -s ftp.kernel.org/pub/linux/kernel/ | \
      perl -lne 'print if s/^d[-rwx]{9}(?: +[^ ]+){7} (.+)$/$1/'

If you need to parse LIST output, libcurl provides the ability to specify a
wildcard to download multiple files from an FTP directory.

## I want a different time-out

Sometimes users realize that `CURLOPT_TIMEOUT` and `CURLOPT_CONNECTTIMEOUT`
are not sufficiently advanced or flexible to cover all the various use cases
and scenarios applications end up with.

libcurl offers many more ways to time-out operations. A common alternative is
to use the `CURLOPT_LOW_SPEED_LIMIT` and `CURLOPT_LOW_SPEED_TIME` options to
specify the lowest possible speed to accept before to consider the transfer
timed out.

The most flexible way is by writing your own time-out logic and using
`CURLOPT_XFERINFOFUNCTION` (perhaps in combination with other callbacks) and
use that to figure out exactly when the right condition is met when the
transfer should get stopped.

## Can I write a server with libcurl?

No. libcurl offers no functions or building blocks to build any kind of
Internet protocol server. libcurl is only a client-side library. For server
libraries, you need to continue your search elsewhere but there exist many
good open source ones out there for most protocols you could want a server
for. There are also really good stand-alone servers that have been tested and
proven for many years. There is no need for you to reinvent them.

## Does libcurl use threads?

No, libcurl executes in the same thread you call it in. All callbacks are
called in the same thread as the one you call libcurl in.

If you want to avoid your thread to be blocked by the libcurl call, you make
sure you use the non-blocking multi API which does transfers
asynchronously - still in the same single thread.

libcurl does potentially internally use threads for name resolving, if it was
built to work like that, but in those cases it creates the child threads by
itself and they are only used and then killed internally by libcurl and never
exposed to the outside.

# License

curl and libcurl are released under an MIT/X derivative license. The license
is liberal and should not impose a problem for your project. This section is a
brief summary for the cases we get the most questions.

We are not lawyers and this is not legal advice. You should probably consult
one if you want true and accurate legal insights without our prejudice. Note
especially that this section concerns the libcurl license only; compiling in
features of libcurl that depend on other libraries (e.g. OpenSSL) may affect
the licensing obligations of your application.

## I have a GPL program, can I use the libcurl library?

Yes

Since libcurl may be distributed under the MIT/X derivative license, it can be
used together with GPL in any software.

## I have a closed-source program, can I use the libcurl library?

Yes

libcurl does not put any restrictions on the program that uses the library.

## I have a BSD licensed program, can I use the libcurl library?

Yes

libcurl does not put any restrictions on the program that uses the library.

## I have a program that uses LGPL libraries, can I use libcurl?

Yes

The LGPL license does not clash with other licenses.

## Can I modify curl/libcurl for my program and keep the changes secret?

Yes

The MIT/X derivative license practically allows you to do almost anything with
the sources, on the condition that the copyright texts in the sources are left
intact.

## Can you please change the curl/libcurl license?

No.

We have carefully picked this license after years of development and
discussions and a large amount of people have contributed with source code
knowing that this is the license we use. This license puts the restrictions we
want on curl/libcurl and it does not spread to other programs or libraries
that use it. It should be possible for everyone to use libcurl or curl in
their projects, no matter what license they already have in use.

## What are my obligations when using libcurl in my commercial apps?

Next to none. All you need to adhere to is the MIT-style license (stated in
the COPYING file) which says you have to include the copyright notice in *all
copies* and that you may not use the copyright holder's name when promoting
your software.

You do not have to release any of your source code.

You do not have to reveal or make public any changes to the libcurl source
code.

You do not have to broadcast to the world that you are using libcurl within
your app.

All we ask is that you disclose *the copyright notice and this permission
notice* somewhere. Most probably like in the documentation or in the section
where other third party dependencies already are mentioned and acknowledged.

As can be seen [here](https://curl.se/docs/companies.html) and elsewhere, more
and more companies are discovering the power of libcurl and take advantage of
it even in commercial environments.

## What license does curl use exactly?

curl is released under an [MIT derivative
license](https://curl.se/docs/copyright.html). It is similar but not identical
to the MIT license.

The difference is considered big enough to make SPDX list it under its own
identifier: [curl](https://spdx.org/licenses/curl.html).

The changes done to the license that make it uniquely curl were tiny and
well-intended, but the reasons for them have been forgotten and we strongly
discourage others from doing the same thing.

# PHP/CURL

## What is PHP/CURL?

The module for PHP that makes it possible for PHP programs to access curl
functions from within PHP.

In the curl project we call this module PHP/CURL to differentiate it from curl
the command line tool and libcurl the library. The PHP team however does not
refer to it like this (for unknown reasons). They call it plain CURL (often
using all caps) or sometimes ext/curl, but both cause much confusion to users
which in turn gives us a higher question load.

## Who wrote PHP/CURL?

PHP/CURL was initially written by Sterling Hughes.

## Can I perform multiple requests using the same handle?

Yes.

After a transfer, you set new options in the handle and make another transfer.
This makes libcurl reuse the same connection if it can.

## Does PHP/CURL have dependencies?

PHP/CURL is a module that comes with the regular PHP package. It depends on
and uses libcurl, so you need to have libcurl installed properly before
PHP/CURL can be used.

# Development

## Why does curl use C89?

As with everything in curl, there is a history and we keep using what we have
used before until someone brings up the subject and argues for and works on
changing it.

We started out using C89 in the 1990s because that was the only way to write a
truly portable C program and have it run as widely as possible. C89 was for a
long time even necessary to make things work on otherwise considered modern
platforms such as Windows. Today, we do not really know how many users that
still require the use of a C89 compiler.

We continue to use C89 for as long as nobody brings up a strong enough reason
for us to change our minds. The core developers of the project do not feel
restricted by this and we are not convinced that going C99 offers us enough
of a benefit to warrant the risk of cutting off a share of users.

## Would curl be rewritten?

In one go: no. Little by little over time? Sure.

Over the years, new languages and clever operating environments come and go.
Every now and then the urge apparently arises to request that we rewrite curl
in another language.

Some the most important properties in curl are maintaining the API and ABI for
libcurl and keeping the behavior for the command line tool. As long as we can
do that, everything else is up for discussion. To maintain the ABI, we
probably have to maintain a certain amount of code in C, and to remain rock
stable, we never risk anything by rewriting a lot of things in one go.
That said, we can certainly offer more and more optional backends written in
other languages, as long as those backends can be plugged in at build-time.
Backends can be written in any language, but should probably provide APIs
usable from C to ease integration and transition.
<!--
Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.

SPDX-License-Identifier: curl
-->

# Features -- what curl can do

## curl tool

- config file support
- multiple URLs in a single command line
- range "globbing" support: [0-13], {one,two,three}
- multiple file upload on a single command line
- redirect stderr
- parallel transfers

## libcurl

- URL RFC 3986 syntax
- custom maximum download time
- custom lowest download speed acceptable
- custom output result after completion
- guesses protocol from hostname unless specified
- supports .netrc
- progress bar with time statistics while downloading
- standard proxy environment variables support
- have run on 101 operating systems and 28 CPU architectures
- selectable network interface for outgoing traffic
- IPv6 support on Unix and Windows
- happy eyeballs dual-stack IPv4 + IPv6 connects
- persistent connections
- SOCKS 4 + 5 support, with or without local name resolving
- *pre-proxy* support, for *proxy chaining*
- supports username and password in proxy environment variables
- operations through HTTP proxy "tunnel" (using CONNECT)
- replaceable memory functions (malloc, free, realloc, etc)
- asynchronous name resolving
- both a push and a pull style interface
- international domain names (IDN)
- transfer rate limiting
- stable API and ABI
- TCP keep alive
- TCP Fast Open
- DNS cache (that can be shared between transfers)
- non-blocking single-threaded parallel transfers
- Unix domain sockets to server or proxy
- DNS-over-HTTPS
- uses non-blocking name resolves
- selectable name resolver backend

## URL API

- parses RFC 3986 URLs
- generates URLs from individual components
- manages "redirects"

## Header API

- easy access to HTTP response headers, from all contexts
- named headers
- iterate over headers

## TLS

- selectable TLS backend(s)
- TLS False Start
- TLS version control
- TLS session resumption
- key pinning
- mutual authentication
- Use dedicated CA cert bundle
- Use OS-provided CA store
- separate TLS options for HTTPS proxy

## HTTP

- HTTP/0.9 responses are optionally accepted
- HTTP/1.0
- HTTP/1.1
- HTTP/2, including multiplexing and server push
- GET
- PUT
- HEAD
- POST
- multipart formpost (RFC 1867-style)
- authentication: Basic, Digest, NTLM (9) and Negotiate (SPNEGO)
  to server and proxy
- resume transfers
- follow redirects
- maximum amount of redirects to follow
- custom HTTP request
- cookie get/send fully parsed
- reads/writes the Netscape cookie file format
- custom headers (replace/remove internally generated headers)
- custom user-agent string
- custom referrer string
- range
- proxy authentication
- time conditions
- via HTTP proxy, HTTPS proxy or SOCKS proxy
- HTTP/2 or HTTP/1.1 to HTTPS proxy
- retrieve file modification date
- Content-Encoding support for deflate, gzip, brotli and zstd
- "Transfer-Encoding: chunked" support in uploads
- HSTS
- alt-svc
- ETags
- HTTP/1.1 trailers, both sending and getting

## HTTPS

- HTTP/3
- using client certificates
- verify server certificate
- via HTTP proxy, HTTPS proxy or SOCKS proxy
- select desired encryption
- select usage of a specific TLS version
- ECH

## FTP

- download
- authentication
- Kerberos 5
- active/passive using PORT, EPRT, PASV or EPSV
- single file size information (compare to HTTP HEAD)
- 'type=' URL support
- directory listing
- directory listing names-only
- upload
- upload append
- upload via http-proxy as HTTP PUT
- download resume
- upload resume
- custom ftp commands (before and/or after the transfer)
- simple "range" support
- via HTTP proxy, HTTPS proxy or SOCKS proxy
- all operations can be tunneled through proxy
- customizable to retrieve file modification date
- no directory depth limit

## FTPS

- implicit `ftps://` support that use SSL on both connections
- explicit "AUTH TLS" and "AUTH SSL" usage to "upgrade" plain `ftp://`
  connection to use SSL for both or one of the connections

## SSH (both SCP and SFTP)

- selectable SSH backend
- known hosts support
- public key fingerprinting
- both password and public key auth

## SFTP

- both password and public key auth
- with custom commands sent before/after the transfer
- directory listing

## TFTP

- download
- upload

## TELNET

- connection negotiation
- custom telnet options
- stdin/stdout I/O

## LDAP

- full LDAP URL support

## DICT

- extended DICT URL support

## FILE

- URL support
- upload
- resume

## SMB

- SMBv1 over TCP and SSL
- download
- upload
- authentication with NTLMv1

## SMTP

- authentication: Plain, Login, CRAM-MD5, Digest-MD5, NTLM, Kerberos 5 and
  External
- send emails
- mail from support
- mail size support
- mail auth support for trusted server-to-server relaying
- multiple recipients
- via http-proxy

## SMTPS

- implicit `smtps://` support
- explicit "STARTTLS" usage to "upgrade" plain `smtp://` connections to use SSL
- via http-proxy

## POP3

- authentication: Clear Text, APOP and SASL
- SASL based authentication: Plain, Login, CRAM-MD5, Digest-MD5, NTLM,
  Kerberos 5 and External
- list emails
- retrieve emails
- enhanced command support for: CAPA, DELE, TOP, STAT, UIDL and NOOP via
  custom requests
- via http-proxy

## POP3S

- implicit `pop3s://` support
- explicit `STLS` usage to "upgrade" plain `pop3://` connections to use SSL
- via http-proxy

## IMAP

- authentication: Clear Text and SASL
- SASL based authentication: Plain, Login, CRAM-MD5, Digest-MD5, NTLM,
  Kerberos 5 and External
- list the folders of a mailbox
- select a mailbox with support for verifying the `UIDVALIDITY`
- fetch emails with support for specifying the UID and SECTION
- upload emails via the append command
- enhanced command support for: EXAMINE, CREATE, DELETE, RENAME, STATUS,
  STORE, COPY and UID via custom requests
- via http-proxy

## IMAPS

- implicit `imaps://` support
- explicit "STARTTLS" usage to "upgrade" plain `imap://` connections to use SSL
- via http-proxy

## MQTT

- Subscribe to and publish topics using URL scheme `mqtt://broker/topic`
<!--
Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.

SPDX-License-Identifier: curl
-->

# Decision making in the curl project

A rough guide to how we make decisions and who does what.

## BDFL

This project was started by and has to some extent been pushed forward over
the years with Daniel Stenberg as the driving force. It matches a standard
BDFL (Benevolent Dictator For Life) style project.

This setup has been used due to convenience and the fact that it has worked
fine this far. It is not because someone thinks of it as a superior project
leadership model. It also only works as long as Daniel manages to listen in to
what the project and the general user population wants and expects from us.

## Legal entity

There is no legal entity. The curl project is a bunch of people scattered
around the globe with the common goal to produce source code that creates
great products. We are not part of any umbrella organization and we are not
located in any specific country. We are totally independent.

The copyrights in the project are owned by the individuals and organizations
that wrote those parts of the code.

## Decisions

The curl project is not a democracy, but everyone is entitled to state their
opinion and may argue for their sake within the community.

All and any changes that have been done or are done are eligible to bring up
for discussion, to object to or to praise. Ideally, we find consensus for the
appropriate way forward in any given situation or challenge.

If there is no obvious consensus, a maintainer who's knowledgeable in the
specific area takes an "executive" decision that they think is the right for
the project.

## Donations

Donating plain money to curl is best done to curl's [Open Collective
fund](https://opencollective.com/curl). Open Collective is a US based
non-profit organization that holds on to funds for us. This fund is used to
reimburse and pay for project related expenses etc.

Donations to the project can also come in the form of server hosting, providing
services and paying for people to work on curl related code etc. Usually, such
donations are services paid for directly by the sponsors.

We grade sponsors in a few different levels and if they meet the criteria,
they can be mentioned on the Sponsors page on the curl website.

## Commercial Support

The curl project does not do or offer commercial support. It only hosts
mailing lists, runs bug trackers etc to facilitate communication and work.

Daniel works for wolfSSL, which offers commercial curl support.

# Key roles

## User

Someone who uses or has used curl or libcurl.

## Contributor

Someone who has helped the curl project, who has contributed to bring it
forward. Contributing could be to provide advice, debug a problem, file a bug
report, run test infrastructure or writing code etc.

## Commit author

Sometimes also called 'committer'. Someone who has authored a commit in the
curl source code repository. Committers are recorded as `Author` in git.

## Maintainers

A maintainer in the curl project is an individual who has been given
permissions to push commits to one of the git repositories.

Maintainers are free to push commits to the repositories at they see fit.
Maintainers are however expected to listen to feedback from users and any
change that is non-trivial in size or nature *should* be brought to the
project as a Pull-Request (PR) to allow others to comment/object before merge.

## Former maintainers

A maintainer who stops being active in the project gets their push permissions
removed at some point. We do this for security reasons but also to make sure
that we always have the list of maintainers as "the team that push stuff to
curl".

Getting push permissions removed is not a punishment. Everyone who ever worked
on maintaining curl is considered a hero, for all time hereafter.

## Security team members

We have a security team. That is the team of people who are subscribed to the
curl-security mailing list; the receivers of security reports from users and
developers. This list of people varies over time but they are all skilled
developers familiar with the curl project.

The security team works best when it consists of a small set of active
persons. We invite new members when the team seems to need it, and we also
expect to retire security team members as they "drift off" from the project or
find themselves unable to perform their duties there.

## Core team

There is a curl core team. It currently has the same set of members as the
security team. It can also be reached on the security email address.

The core team nominates and invites new members to the team when it sees fit.
There is no open member voting or formal ways to be a candidate. Active
participants in the curl project who want to join the core team can ask to
join.

The core team is a board of advisors. It deals with project management
subjects that need confidentiality or for other reasons cannot be dealt with
and discussed in the open (for example reports of code of conduct violations).
Project matters should always as far as possible be discussed on open mailing
lists.

## Server admins

We run a web server, a mailing list and more on the curl project's primary
server. That physical machine is owned and run by Haxx. Daniel is the primary
admin of all things curl related server stuff, but Björn Stenberg and Linus
Feltzing serve as backup admins for when Daniel is gone or unable.

The primary server is paid for by Haxx. The machine is physically located in a
server bunker in Stockholm Sweden, operated by the company Glesys.

The website contents are served to the web via Fastly and Daniel is the
primary curl contact with Fastly.

## BDFL

That is Daniel.

# Maintainers

A curl maintainer is a project volunteer who has the authority and rights to
merge changes into a git repository in the curl project.

Anyone can aspire to become a curl maintainer.

### Duties

There are no mandatory duties. We hope and wish that maintainers consider
reviewing patches and help merging them, especially when the changes are
within the area of personal expertise and experience.

### Requirements

- only merge code that meets our quality and style guide requirements.
- *never* merge code without doing a PR first, unless the change is "trivial"
- if in doubt, ask for input/feedback from others

### Recommendations

- we require two-factor authentication enabled on your GitHub account to
  reduce risk of malicious source code tampering
- consider enabling signed git commits for additional verification of changes

### Merge advice

When you are merging patches/pull requests...

- make sure the commit messages follow our template
- squash patch sets into a few logical commits even if the PR did not, if
  necessary
- avoid the "merge" button on GitHub, do it "manually" instead to get full
  control and full audit trail (GitHub leaves out you as "Committer:")
- remember to credit the reporter and the helpers.

## Who are maintainers?

The [list of maintainers](https://github.com/orgs/curl/people). Be aware that
the level of presence and activity in the project vary greatly between
different individuals and over time.

### Become a maintainer?

If you think you can help making the project better by shouldering some
maintaining responsibilities, then please get in touch.

You are expected to be familiar with the curl project and its ways of working.
You need to have gotten a few quality patches merged as a proof of this.

### Stop being a maintainer

If you (appear to) not be active in the project anymore, you may be removed as
a maintainer. Thank you for your service.

# Post-Daniel BDFL

At the point in a future when Daniel steps away from the project and stops
being the project lead, there is reason to reconsider how to keep driving the
project forward. Countries, companies and organizations have a single
president or CEO for a reason; having a single leader that responsibly can
take quick daily decisions is efficient. Without Daniel as BDFL, either
someone else needs to step up and become president, or the project needs to
adopt a council-driven process. Maybe both? Maybe vote a new project leader
for one year or a few years at a time?

Deciding the replacement person and governance is a subject for the curl core
team to vote on. When that happens, this section of this document should also
get updated.
<!--
Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.

SPDX-License-Identifier: curl
-->

# How to get started helping out in the curl project

We are always in need of more help. If you are new to the project and are
looking for ways to contribute and help out, this document aims to give a few
good starting points.

You may subscribe to the [curl-library mailing
list](https://lists.haxx.se/listinfo/curl-library) to keep track of the
current discussion topics; or if you are registered on GitHub, you can use the
[Discussions section](https://github.com/curl/curl/discussions) on the main
curl repository.

## Scratch your own itch

One of the best ways is to start working on any problems or issues you have
found yourself or perhaps got annoyed at in the past. It can be a spelling
error in an error text or a weirdly phrased section in a man page. Hunt it
down and report the bug. Or make your first pull request with a fix for that.

## Smaller tasks

Some projects mark small issues as "beginner friendly", "bite-sized" or
similar. We do not do that in curl since such issues never linger around long
enough. Simple issues get handled fast.

If you are looking for a smaller or simpler task in the project to help out
with as an entry-point into the project, perhaps because you are a newcomer or
even maybe not a terribly experienced developer, here's our advice:

- Read through this document to get a grasp on a general approach to use
- Consider adding a test case for something not currently tested (correctly)
- Consider updating or adding documentation
- One way to get started gently in the project, is to participate in an
  existing issue/PR and help out by reproducing the issue, review the code in
  the PR etc.

## Help wanted

In the issue tracker we occasionally mark bugs with [help
wanted](https://github.com/curl/curl/labels/help%20wanted), as a sign that the
bug is acknowledged to exist and that there is nobody known to work on this
issue for the moment. Those are bugs that are fine to "grab" and provide a
pull request for. The complexity level of these of course varies, so pick one
that piques your interest.

## Work on known bugs

Some bugs are known and have not yet received attention and work enough to get
fixed. We collect such known existing flaws in the
[KNOWN_BUGS](https://curl.se/docs/knownbugs.html) page. Many of them link
to the original bug report with some additional details, but some may also
have aged a bit and may require some verification that the bug still exists in
the same way and that what was said about it in the past is still valid.

## Fix autobuild problems

On the [autobuilds page](https://curl.se/dev/builds.html) we show a
collection of test results from the automatic curl build and tests that are
performed by volunteers. Fixing compiler warnings and errors shown there is
something we value greatly. Also, if you own or run systems or architectures
that are not already tested in the autobuilds, we also appreciate more
volunteers running builds automatically to help us keep curl portable.

## TODO items

Ideas for features and functions that we have considered worthwhile to
implement and provide are kept in the
[TODO](https://curl.se/docs/todo.html) file. Some of the ideas are
rough. Some are well thought out. Some probably are not really suitable
anymore.

Before you invest a lot of time on a TODO item, do bring it up for discussion
on the mailing list. For discussion on applicability but also for ideas and
brainstorming on specific ways to do the implementation etc.

## You decide

You can also come up with a completely new thing you think we should do. Or
not do. Or fix. Or add to the project. You then either bring it to the mailing
list first to see if people shoot down the idea at once, or you bring a first
draft of the idea as a pull request and take the discussion there around the
specific implementation. Either way is fine.

## CONTRIBUTE

We offer [guidelines](https://curl.se/dev/contribute.html) that are suitable
to be familiar with before you decide to contribute to curl. If you are used
to open source development, you probably do not find many surprises there.
<!--
Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.

SPDX-License-Identifier: curl
-->

# How curl Became Like This

Towards the end of 1996, Daniel Stenberg was spending time writing an IRC bot
for an Amiga related channel on EFnet. He then came up with the idea to make
currency-exchange calculations available to Internet Relay Chat (IRC) users.
All the necessary data were published on the Web; he only needed to automate
their retrieval.

## 1996

On November 11, 1996 the Brazilian developer Rafael Sagula wrote and released
HttpGet version 0.1.

Daniel extended this existing command-line open-source tool. After a few minor
adjustments, it did what he needed. The first release with Daniel's additions
was 0.2, released on December 17, 1996. Daniel quickly became the new
maintainer of the project.

## 1997

HttpGet 0.3 was released in January 1997 and now it accepted HTTP URLs on the
command line.

HttpGet 1.0 was released on April 8 1997 with brand new HTTP proxy support.

We soon found and fixed support for getting currencies over GOPHER. Once FTP
download support was added, the name of the project was changed and urlget 2.0
was released in August 1997. The http-only days were already passed.

Version 2.2 was released on August 14 1997 and introduced support to build for
and run on Windows and Solaris.

November 24 1997: Version 3.1 added FTP upload support.

Version 3.5 added support for HTTP POST.

## 1998

February 4: urlget 3.10

February 9: urlget 3.11

March 14: urlget 3.12 added proxy authentication.

The project slowly grew bigger. With upload capabilities, the name was once
again misleading and a second name change was made. On March 20, 1998 curl 4
was released. (The version numbering from the previous names was kept.)

(Unrelated to this project a company called Curl Corporation registered a US
trademark on the name "CURL" on May 18 1998. That company had then already
registered the curl.com domain back in November of the previous year. All this
was revealed to us much later.)

SSL support was added, powered by the SSLeay library.

August: first announcement of curl on freshmeat.net.

October: with the curl 4.9 release and the introduction of cookie support,
curl was no longer released under the GPL license. Now we are at 4000 lines of
code, we switched over to the MPL license to restrict the effects of
"copyleft".

November: configure script and reported successful compiles on several
major operating systems. The often-misunderstood -F option was added, and
curl could now simulate significant browser functionality. TELNET support was
added.

curl 5 was released in December 1998 and introduced the first ever curl man
page. People started making Linux RPM packages out of it.

## 1999

January: DICT support added.

OpenSSL took over and SSLeay was abandoned.

May: first Debian package.

August: `ldap://` and `file://` support added. The curl website gets 1300
visits weekly. Moved site to curl.haxx.nu.

September: started using CVS for source code version control.

September: Released curl 6.0. 15000 lines of code.

December 28: added the project on Sourceforge and started using its services
for managing the project.

## 2000

Spring: major internal overhaul to provide a suitable library interface.
The first non-beta release was named 7.1 and arrived in August. This offered
the easy interface and turned out to be the beginning of actually getting
other software and programs to be based on and powered by libcurl. Almost
20000 lines of code.

June: the curl site moves to "curl.haxx.se"

August, the curl website gets 4000 visits weekly.

The PHP guys adopted libcurl already the same month, when the first ever third
party libcurl binding showed up. CURL has been a supported module in PHP since
the release of PHP 4.0.2. This would soon get followers. More than 16
different bindings exist at the time of this writing.

September: kerberos4 support was added.

November: started the work on a test suite for curl. It was later re-written
from scratch again. The libcurl major SONAME number was set to 1.

## 2001

January: Daniel released curl 7.5.2 under a new license again: MIT (or
MPL). The MIT license is extremely liberal and can be combined with GPL
in other projects. This would finally put an end to the "complaints" from
people involved in GPLed projects that previously were prohibited from using
libcurl while it was released under MPL only. (Due to the fact that MPL is
deemed "GPL incompatible".)

March 22: curl supports HTTP 1.1 starting with the release of 7.7. This
also introduced libcurl's ability to do persistent connections. 24000 lines of
code. The libcurl major SONAME number was bumped to 2 due to this overhaul.
The first experimental `ftps://` support was added.

August: The curl website gets 8000 visits weekly. Curl Corporation contacted
Daniel to discuss "the name issue". After Daniel's reply, they have never
since got back in touch again.

September: libcurl 7.9 introduces cookie jar and `curl_formadd()`. During the
forthcoming 7.9.x releases, we introduced the multi interface slowly and
without many whistles.

September 25: curl (7.7.2) is bundled in Mac OS X (10.1) for the first time. It was
already becoming more and more of a standard utility of Linux distributions
and a regular in the BSD ports collections.

## 2002

June: the curl website gets 13000 visits weekly. curl and libcurl is
35000 lines of code. Reported successful compiles on more than 40 combinations
of CPUs and operating systems.

To estimate the number of users of the curl tool or libcurl library is next to
impossible. Around 5000 downloaded packages each week from the main site gives
a hint, but the packages are mirrored extensively, bundled with numerous OS
distributions and otherwise retrieved as part of other software.

October 1: with the release of curl 7.10 it is released under the MIT license
only.

Starting with 7.10, curl verifies SSL server certificates by default.

## 2003

January: Started working on the distributed curl tests. The autobuilds.

February: the curl site averages at 20000 visits weekly. At any given moment,
there is an average of 3 people browsing the website.

Multiple new authentication schemes are supported: Digest (May), NTLM (June)
and Negotiate (June).

November: curl 7.10.8 is released. 45000 lines of code. ~55000 unique visitors
to the website. Five official web mirrors.

December: full-fledged SSL for FTP is supported.

## 2004

January: curl 7.11.0 introduced large file support.

March: added asynch name resolves using the c-ares library

June: curl 7.12.0 introduced IDN support. 10 official web mirrors.

This release bumped the major SONAME to 3 due to the removal of the
`curl_formparse()` function

August: curl and libcurl 7.12.1

    Public curl release number:                82
    Releases counted from the beginning:      109
    Available command line options:            96
    Available curl_easy_setopt() options:     120
    Number of public functions in libcurl:     36
    Amount of public website mirrors:          12
    Number of known libcurl bindings:          26

## 2005

April: GnuTLS can now optionally be used for the secure layer when curl is
built.

April: Added the multi_socket() API

September: TFTP support was added.

More than 100,000 unique visitors of the curl website. 25 mirrors.

December: security vulnerability: libcurl URL Buffer Overflow

## 2006

January: We dropped support for Gopher. We found bugs in the implementation
that turned out to have been introduced years ago, so with the conclusion that
nobody had found out in all this time we removed it instead of fixing it.

March: security vulnerability: libcurl TFTP Packet Buffer Overflow

September: The major SONAME number for libcurl was bumped to 4 due to the
removal of ftp third party transfer support.

October: we started to offer the Mozilla CA cert bundle as a PEM file on the
curl website.

November: Added SCP and SFTP support

## 2007

February: Added support for the Mozilla NSS library to do the SSL/TLS stuff

July: security vulnerability: libcurl GnuTLS insufficient cert verification

## 2008

November:

    Command line options:         128
    curl_easy_setopt() options:   158
    Public functions in libcurl:   58
    Known libcurl bindings:        37
    Contributors:                 683

145,000 unique visitors. >100 GB downloaded.

## 2009

March: security vulnerability: libcurl Arbitrary File Access

April: added CMake support

August: security vulnerability: libcurl embedded zero in cert name

December: Added support for IMAP, POP3 and SMTP

## 2010

January: Added support for RTSP

February: security vulnerability: libcurl data callback excessive length

March: The project switched over to use git (hosted by GitHub) instead of CVS
for source code control

May: Added support for RTMP

Added support for PolarSSL to do the SSL/TLS stuff

August:

    Public curl releases:         117
    Command line options:         138
    curl_easy_setopt() options:   180
    Public functions in libcurl:   58
    Known libcurl bindings:        39
    Contributors:                 808

Gopher support added (re-added actually, see January 2006)

## 2011

February: added support for the axTLS backend

April: added the cyassl backend (later renamed to wolfSSL)

## 2012

July: Added support for Schannel (native Windows TLS backend) and Darwin SSL
(Native Mac OS X and iOS TLS backend).

Supports Metalink

October: SSH-agent support.

## 2013

February: Cleaned up internals to always uses the "multi" non-blocking
approach internally and only expose the blocking API with a wrapper.

September: First small steps on supporting HTTP/2 with nghttp2.

October: Removed krb4 support.

December: Happy eyeballs.

## 2014

March: first real release supporting HTTP/2

September: Website had 245,000 unique visitors and served 236GB data

SMB and SMBS support

## 2015

June: support for multiplexing with HTTP/2

August: support for HTTP/2 server push

September: started "everything curl". A separate stand-alone book documenting
curl and related info in perhaps a more tutorial style rather than a
reference,

September: initial support for the Public Suffix List for cookies.

December: Public Suffix List

## 2016

January: the curl tool defaults to HTTP/2 for HTTPS URLs

June 26: Rafael Sagula, author of the original httpget tool in 1996 died.

December: curl 7.52.0 introduced support for HTTPS-proxy

First TLS 1.3 support

## 2017

May: Fastly starts hosting the curl website

July: OSS-Fuzz started fuzzing libcurl

September: Added MultiSSL support

The website serves 3100 GB/month

   Public curl releases:         169
   Command line options:         211
   curl_easy_setopt() options:   249
   Public functions in libcurl:  74
   Contributors:                 1609

October: SSLKEYLOGFILE support, new MIME API

October: Daniel received the Polhem Prize for his work on curl

November: brotli

## 2018

January: new SSH backend powered by libssh

March: starting with the 1803 release of Windows 10, curl is shipped bundled
with Microsoft's operating system.

July: curl shows headers using bold type face

October: added DNS-over-HTTPS (DoH) and the URL API

MesaLink is a new supported TLS backend

libcurl now does HTTP/2 (and multiplexing) by default on HTTPS URLs

curl and libcurl are installed in an estimated 5 *billion* instances
world-wide.

October 31: curl and libcurl 7.62.0

   Public curl releases:         177
   Command line options:         219
   curl_easy_setopt() options:   261
   Public functions in libcurl:  80
   Contributors:                 1808

December: removed axTLS support

## 2019

January: Daniel started working full-time on curl, employed by wolfSSL

March: added experimental alt-svc support

August: the first HTTP/3 requests with curl.

September: 7.66.0 is released and the tool offers parallel downloads

## 2020

curl and libcurl are installed in an estimated 10 *billion* instances
world-wide.

January: added BearSSL support

March: removed support for PolarSSL, added wolfSSH support. Created the first
dashboard on the website.

April: experimental MQTT support

August: zstd support

November: the website moves to curl.se. The website serves 10TB data monthly.

December: alt-svc support

## 2021

February 3: curl 7.75.0 ships with support for Hyper as an HTTP backend

March 31: curl 7.76.0 ships with support for Rustls

July: HSTS is supported

## 2022

March: added --json, removed mesalink support

    Public curl releases:         206
    Command line options:         245
    curl_easy_setopt() options:   295
    Public functions in libcurl:  86
    Contributors:                 2601

The curl.se website serves 16,500 GB/month over 462M requests, the
official docker image has been pulled 4,098,015,431 times.

April: added support for msh3 as another HTTP/3 backend

October: initial WebSocket support

## 2023

March: remove support for curl_off_t < 8 bytes

March 31: we started working on a new command line tool for URL parsing and
manipulations: trurl.

May: added support for HTTP/2 over HTTPS proxy. Refuse to resolve .onion. The
curl GitHub repository reaches 30,000 stars.

August: Dropped support for the NSS library

September: added "variable" support in the command line tool. Dropped support
for the gskit TLS library.

October: added support for IPFS via HTTP gateway

December: HTTP/3 support with ngtcp2 is no longer experimental

## 2024

January: switched to "curldown" for all documentation

April 24: the curl container has been pulled more than six billion times

May: experimental support for ECH, dropped NTLM_WB

August 9: we adopted the wcurl tool into the curl organization

September 11: --help [option]

November 6: TLS 1.3 early data, WebSocket is official

December 21: dropped hyper

## 2025

February 5: first 0RTT for QUIC, SSL session import/export

February: experimental HTTPS RR support

February 22: The website served 62.95 TB/month; 12.43 billion requests. The
docker image has been pulled 6373501745 times.

June: we removed support for BearSSL, Secure Transport and msh3

October: Daniel gets awarded a gold medal by the Swedish Royal Academy of
Engineering Sciences for his work on curl.

We counted curl having been installed on 110 operating systems and 28 CPU
architectures.

November:

    Public curl releases:         271
    Command line options:         273
    curl_easy_setopt() options:   308
    Public functions in libcurl:  100
    Contributors:                 3534

We drop support for krb-ftp, Heimdal, wolfSSH and the winbuild build system.

Add support for Apple SecTrust, native CA certs on Apple systems.

December 15: the website served 78 TB over the last month.

## 2026

April: removed support for RTMP
<!--
Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.

SPDX-License-Identifier: curl
-->

# HSTS support

HTTP Strict-Transport-Security. Added as experimental in curl
7.74.0. Supported "for real" since 7.77.0.

## Standard

[HTTP Strict Transport Security](https://datatracker.ietf.org/doc/html/rfc6797)

## Behavior

libcurl features an in-memory cache for HSTS hosts, so that subsequent
HTTP-only requests to a hostname present in the cache gets internally
"redirected" to the HTTPS version.

Since curl 8.20.0, libcurl keeps no more than the most recently added 10,000
unique HSTS hostnames.

## `curl_easy_setopt()` options:

- `CURLOPT_HSTS_CTRL` - enable HSTS for this easy handle
- `CURLOPT_HSTS` - specify filename where to store the HSTS cache on close
  (and possibly read from at startup)

## curl command line options

- `--hsts [filename]` - enable HSTS, use the file as HSTS cache. If filename
  is `""` (no length) then no file is used, only in-memory cache.

## HSTS cache file format

Lines starting with `#` are ignored.

For each hsts entry:

    [hostname] "YYYYMMDD HH:MM:SS"

The `[hostname]` is dot-prefixed if it includes subdomains.

The time stamp is when the entry expires.

## Possible future additions

- `CURLOPT_HSTS_PRELOAD` - provide a set of HSTS hostnames to load first
- ability to save to something else than a file
<!--
Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.

SPDX-License-Identifier: curl
-->

# HTTP3 (and QUIC)

## Resources

[HTTP/3 Explained](https://http3-explained.haxx.se/en/) - the online free
book describing the protocols involved.

[quicwg.org](https://quicwg.org/) - home of the official protocol drafts

## QUIC libraries

QUIC libraries we are using:

[ngtcp2](https://github.com/ngtcp2/ngtcp2)

[quiche](https://github.com/cloudflare/quiche) - **EXPERIMENTAL**

## Experimental

HTTP/3 support using *quiche* in curl is considered **EXPERIMENTAL** until
further notice. Only the *ngtcp2* backend is not experimental.

Further development and tweaking of the HTTP/3 support in curl happens in the
master branch using pull-requests like ordinary changes.

To fix before we remove the experimental label:

- the used QUIC library needs to consider itself non-beta
- it is fine to "leave" individual backends as experimental if necessary

# ngtcp2 version

Building curl with ngtcp2 involves 3 components: `ngtcp2` itself, `nghttp3`
and a QUIC supporting TLS library. The supported TLS libraries are covered
below.

While any version of `ngtcp2` and `nghttp3` from v1.0.0 on are expected to
work, using the latest versions often brings functional and performance
improvements.

The build examples use `$NGHTTP3_VERSION` and `$NGTCP2_VERSION` as
placeholders for the version you build.

## Build with OpenSSL or fork

OpenSSL v3.5.0+ requires *ngtcp2* v1.12.0+. Earlier versions do not work.

Build OpenSSL (v3.5.0+) or fork AWS-LC, BoringSSL, LibreSSL or quictls:

     # Instructions for OpenSSL v3.5.0+
     % git clone --depth 1 --branch openssl-$OPENSSL_VERSION https://github.com/openssl/openssl
     % cd openssl
     % ./config --prefix=/path/to/openssl --libdir=lib
     % make
     % make install

Build nghttp3:

     % cd ..
     % git clone --depth 1 --branch $NGHTTP3_VERSION https://github.com/ngtcp2/nghttp3
     % cd nghttp3
     % git submodule update --init
     % autoreconf -fi
     % ./configure --prefix=/path/to/nghttp3 --enable-lib-only
     % make
     % make install

Build ngtcp2:

     % cd ..
     % git clone --depth 1 --branch $NGTCP2_VERSION https://github.com/ngtcp2/ngtcp2
     % cd ngtcp2
     % autoreconf -fi
     # Change --with-openssl to --with-boringssl for AWS-LC and BoringSSL
     % ./configure PKG_CONFIG_PATH=/path/to/openssl/lib/pkgconfig:/path/to/nghttp3/lib/pkgconfig LDFLAGS="-Wl,-rpath,/path/to/openssl/lib" \
       --prefix=/path/to/ngtcp2 --enable-lib-only --with-openssl
     % make
     % make install

Build curl (with autotools):

     % cd ..
     % git clone --depth 1 https://github.com/curl/curl
     % cd curl
     % autoreconf -fi
     % ./configure PKG_CONFIG_PATH=/path/to/openssl/lib/pkgconfig LDFLAGS="-Wl,-rpath,/path/to/openssl/lib" \
       --with-openssl=/path/to/openssl --with-ngtcp2=/path/to/ngtcp2 --with-nghttp3=/path/to/nghttp3
     % make
     % make install

Build curl (with CMake):

     % cd ..
     % git clone --depth 1 https://github.com/curl/curl
     % cd curl
     % PKG_CONFIG_PATH=/path/to/openssl/lib/pkgconfig:/path/to/ngtcp2/lib/pkgconfig:/path/to/nghttp3/lib/pkgconfig cmake -B bld \
       -DOPENSSL_ROOT_DIR=/path/to/openssl -DUSE_NGTCP2=ON
     % cmake --build bld

## Build with GnuTLS

Build GnuTLS:

     % git clone --depth 1 https://gitlab.com/gnutls/gnutls
     % cd gnutls
     % ./bootstrap
     % ./configure --prefix=/path/to/gnutls
     % make
     % make install

Build nghttp3:

     % cd ..
     % git clone --depth 1 --branch $NGHTTP3_VERSION https://github.com/ngtcp2/nghttp3
     % cd nghttp3
     % git submodule update --init
     % autoreconf -fi
     % ./configure --prefix=/path/to/nghttp3 --enable-lib-only
     % make
     % make install

Build ngtcp2:

     % cd ..
     % git clone --depth 1 --branch $NGTCP2_VERSION https://github.com/ngtcp2/ngtcp2
     % cd ngtcp2
     % autoreconf -fi
     % ./configure PKG_CONFIG_PATH=/path/to/gnutls/lib/pkgconfig:/path/to/nghttp3/lib/pkgconfig LDFLAGS="-Wl,-rpath,/path/to/gnutls/lib" \
       --prefix=/path/to/ngtcp2 --enable-lib-only --with-gnutls
     % make
     % make install

Build curl (with autotools):

     % cd ..
     % git clone --depth 1 https://github.com/curl/curl
     % cd curl
     % autoreconf -fi
     % ./configure PKG_CONFIG_PATH=/path/to/gnutls/lib/pkgconfig --with-gnutls=/path/to/gnutls --with-ngtcp2=/path/to/ngtcp2 --with-nghttp3=/path/to/nghttp3
     % make
     % make install

Build curl (with CMake):

     % cd ..
     % git clone --depth 1 https://github.com/curl/curl
     % cd curl
     % PKG_CONFIG_PATH=/path/to/gnutls/lib/pkgconfig:/path/to/ngtcp2/lib/pkgconfig:/path/to/nghttp3/lib/pkgconfig cmake -B bld -DCURL_USE_GNUTLS=ON -DUSE_NGTCP2=ON
     % cmake --build bld

## Build with wolfSSL

Build wolfSSL:

     % git clone --depth 1 https://github.com/wolfSSL/wolfssl
     % cd wolfssl
     % autoreconf -fi
     % ./configure --prefix=/path/to/wolfssl --enable-quic --enable-session-ticket --enable-earlydata --enable-psk --enable-harden --enable-altcertchains
     % make
     % make install

Build nghttp3:

     % cd ..
     % git clone --depth 1 --branch $NGHTTP3_VERSION https://github.com/ngtcp2/nghttp3
     % cd nghttp3
     % git submodule update --init
     % autoreconf -fi
     % ./configure --prefix=/path/to/nghttp3 --enable-lib-only
     % make
     % make install

Build ngtcp2:

     % cd ..
     % git clone --depth 1 --branch $NGTCP2_VERSION https://github.com/ngtcp2/ngtcp2
     % cd ngtcp2
     % autoreconf -fi
     % ./configure PKG_CONFIG_PATH=/path/to/wolfssl/lib/pkgconfig:/path/to/nghttp3/lib/pkgconfig LDFLAGS="-Wl,-rpath,/path/to/wolfssl/lib" \
       --prefix=/path/to/ngtcp2 --enable-lib-only --with-wolfssl
     % make
     % make install

Build curl (with autotools):

     % cd ..
     % git clone --depth 1 https://github.com/curl/curl
     % cd curl
     % autoreconf -fi
     % ./configure PKG_CONFIG_PATH=/path/to/wolfssl/lib/pkgconfig --with-wolfssl=/path/to/wolfssl --with-ngtcp2=/path/to/ngtcp2 --with-nghttp3=/path/to/nghttp3
     % make
     % make install

Build curl (with CMake):

     % cd ..
     % git clone --depth 1 https://github.com/curl/curl
     % cd curl
     % PKG_CONFIG_PATH=/path/to/wolfssl/lib/pkgconfig:/path/to/ngtcp2/lib/pkgconfig:/path/to/nghttp3/lib/pkgconfig cmake -B bld -DCURL_USE_WOLFSSL=ON -DUSE_NGTCP2=ON
     % cmake --build bld

# quiche version

quiche support is **EXPERIMENTAL**

Since the quiche build manages its dependencies, curl can be built against the
latest version. You are *probably* able to build against their main branch,
but in case of problems, we recommend their latest release tag.

## Build

Build quiche and BoringSSL (described here for quiche v0.29.1, the locations
where BoringSSL is to be found vary with version):

     % git clone --depth 1 --branch 0.29.1 --recursive https://github.com/cloudflare/quiche
     % cd quiche
     % cargo build --package quiche --release --features ffi,pkg-config-meta,qlog
     % ln -s libquiche.so target/release/libquiche.so.0
     % mkdir -p boringssl/lib
     % find target/release \( -name libcrypto.a -o -name libssl.a \) -exec ln -vnf -- '{}' boringssl/lib \;
     % find target/release/build/boring-sys-*/out/boringssl/src -maxdepth 1 \( -name include \) -exec ln -vsf -- '../{}' boringssl \;

Build curl:

     % cd ..
     % git clone --depth 1 https://github.com/curl/curl
     % cd curl
     % autoreconf -fi
     % ./configure --with-openssl=$PWD/../quiche/boringssl --with-quiche=$PWD/../quiche/target/release
     % make
     % make install

If `make install` results in `Permission denied` error, you need to prepend
it with `sudo`.

# `--http3`

Use only HTTP/3:

     % curl --http3-only https://example.org:4433/

Use HTTP/3 with fallback to HTTP/2 or HTTP/1.1 (see "HTTPS eyeballing" below):

     % curl --http3 https://example.org:4433/

Upgrade via Alt-Svc:

     % curl --alt-svc altsvc.cache https://curl.se/

See this [list of public HTTP/3 servers](https://bagder.github.io/HTTP3-test/)

### HTTPS eyeballing

With option `--http3` curl attempts earlier HTTP versions as well should the
connect attempt via HTTP/3 fail "fast enough". This strategy is similar
to IPv4/6 happy eyeballing where the alternate address family is used in
parallel after a short delay.

The IPv4/6 eyeballing has a default of 200ms and you may override that via
`--happy-eyeballs-timeout-ms value`. Since HTTP/3 is still relatively new, we
decided to use this timeout also for the HTTP eyeballing - with a slight
twist.

The `happy-eyeballs-timeout-ms` value is the **hard** timeout, meaning after
that time expired, a TLS connection is opened in addition to negotiate HTTP/2
or HTTP/1.1. At half of that value - currently - is the **soft** timeout. The
soft timeout fires, when there has been **no data at all** seen from the
server on the HTTP/3 connection.

Without you specifying anything, the hard timeout is 200ms and the soft is
100ms:

* Ideally, the whole QUIC handshake happens and curl has an HTTP/3 connection
  in less than 100ms.
* When QUIC is not supported (or UDP does not work for this network path), no
  reply is seen and the HTTP/2 TLS+TCP connection starts 100ms later.
* In the worst case, UDP replies start before 100ms, but drag on. This starts
  the TLS+TCP connection after 200ms.
* When the QUIC handshake fails, the TLS+TCP connection is attempted right
  away. For example, when the QUIC server presents the wrong certificate.

The whole transfer only fails, when **both** QUIC and TLS+TCP fail to
handshake or time out.

Note that all this happens in addition to IP version happy eyeballing. If the
name resolution for the server gives more than one IP address, curl tries all
those until one succeeds - as with all other protocols. If those IP addresses
contain both IPv6 and IPv4, those attempts happen, delayed, in parallel (the
actual eyeballing).

## Known Bugs

Check out the [list of known HTTP3 bugs](https://curl.se/docs/knownbugs.html#HTTP3).

# HTTP/3 Test server

This is not advice on how to run anything in production. This is for
development and experimenting.

## Prerequisite(s)

An existing local HTTP/1.1 server that hosts files. Preferably also a few huge
ones. You can easily create huge local files like `truncate -s=8G 8GB` - they
are huge but do not occupy that much space on disk since they are big holes.

In a Debian setup you can install apache2. It runs on port 80 and has a
document root in `/var/www/html`. Download the 8GB file from apache with `curl
localhost/8GB -o dev/null`

In this description we setup and run an HTTP/3 reverse-proxy in front of the
HTTP/1 server.

## Setup

You can select either or both of these server solutions.

### nghttpx

Get, build and install quictls, nghttp3 and ngtcp2 as described
above.

Get, build and install nghttp2:

     % git clone --depth 1 https://github.com/nghttp2/nghttp2
     % cd nghttp2
     % autoreconf -fi
     % PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/path/to/quictls/lib/pkgconfig:/path/to/nghttp3/lib/pkgconfig:/path/to/ngtcp2/lib/pkgconfig \
       LDFLAGS=-L/path/to/quictls/lib CFLAGS=-I/path/to/quictls/include ./configure --enable-maintainer-mode \
       --prefix=/path/to/nghttp2 --disable-shared --enable-app --enable-http3 --without-jemalloc --without-libxml2 --without-systemd
     % make && make install

Run the local h3 server on port 9443, make it proxy all traffic through to
HTTP/1 on localhost port 80. For local toying, we can use the test cert that
exists in curl's test dir.

     % CERT=/path/to/stunnel.pem
     % $HOME/bin/nghttpx $CERT $CERT --backend=localhost,80 \
       --frontend="localhost,9443;quic"

### Caddy

[Install Caddy](https://caddyserver.com/docs/install). For easiest use, the
binary should be either in your PATH or your current directory.

Create a `Caddyfile` with the following content:
~~~
localhost:7443 {
  respond "Hello, world! you are using {http.request.proto}"
}
~~~

Then run Caddy:

     % ./caddy start

Making requests to `https://localhost:7443` should tell you which protocol is
being used.

You can change the hard-coded response to something more useful by replacing
`respond` with `reverse_proxy` or `file_server`, for example: `reverse_proxy
localhost:80`
<!--
Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.

SPDX-License-Identifier: curl
-->

# HTTP Cookies

## Cookie overview

Cookies are `name=contents` pairs that an HTTP server tells the client to
hold and then the client sends back those to the server on subsequent
requests to the same domains and paths for which the cookies were set.

Cookies are either "session cookies" which typically are forgotten when the
session is over which is often translated to equal when browser quits, or
the cookies are not session cookies they have expiration dates after which
the client throws them away.

Cookies are set to the client with the Set-Cookie: header and are sent to
servers with the Cookie: header.

For a long time, the only spec explaining how to use cookies was the
original [Netscape spec from 1994](https://curl.se/rfc/cookie_spec.html).

In 2011, [RFC 6265](https://datatracker.ietf.org/doc/html/rfc6265) was finally
published and details how cookies work within HTTP. In 2016, an update which
added support for prefixes was
[proposed](https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-cookie-prefixes-00),
and in 2017, another update was
[drafted](https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-cookie-alone-01)
to deprecate modification of 'secure' cookies from non-secure origins. Both
of these drafts have been incorporated into a proposal to
[replace](https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-rfc6265bis-11)
RFC 6265. Cookie prefixes and secure cookie modification protection has been
implemented by curl.

curl considers `http://localhost` to be a *secure context*, meaning that it
allows and uses cookies marked with the `secure` keyword even when done over
plain HTTP for this host. curl does this to match how popular browsers work
with secure cookies.

## Super cookies

A single cookie can be set for a domain that matches multiple hosts. Like if
set for `example.com` it gets sent to both `aa.example.com` as well as
`bb.example.com`.

A challenge with this concept is that there are certain domains for which
cookies should not be allowed at all, because they are *Public
Suffixes*. Similarly, a client never accepts cookies set directly for the
top-level domain like for example `.com`. Cookies set for *too broad*
domains are generally referred to as *super cookies*.

If curl is built with PSL (**Public Suffix List**) support, it detects and
discards cookies that are specified for such suffix domains that should not
be allowed to have cookies.

if curl is *not* built with PSL support, it has no ability to stop super
cookies.

## Cookies saved to disk

Netscape once created a file format for storing cookies on disk so that they
would survive browser restarts. curl adopted that file format to allow
sharing the cookies with browsers, only to see browsers move away from that
format. Modern browsers no longer use it, while curl still does.

The Netscape cookie file format stores one cookie per physical line in the
file with a bunch of associated meta data, each field separated with
TAB. That file is called the cookie jar in curl terminology.

When libcurl saves a cookie jar, it creates a file header of its own in
which there is a URL mention that links to the web version of this document.

## Cookie file format

The cookie file format is text based and stores one cookie per line. Lines
that start with `#` are treated as comments. An exception is lines that
start with `#HttpOnly_`, which is a prefix for cookies that have the
`HttpOnly` attribute set.

Each line that specifies a single cookie consists of seven text fields
separated with TAB characters. A valid line must end with a newline
character.

### Fields in the file

Field number, what type and example data and the meaning of it:

0. string `example.com` - the domain name
1. boolean `FALSE` - include subdomains
2. string `/foobar/` - path
3. boolean `TRUE` - send/receive over HTTPS only
4. number `1462299217` - expires at - seconds since Jan 1st 1970, or 0
5. string `person` - name of the cookie
6. string `daniel` - value of the cookie

## Cookies with curl the command line tool

curl has a full cookie "engine" built in. If you activate it, you can have
curl receive and send cookies exactly as mandated in the specs.

Command line options:

[`-b, --cookie`](https://curl.se/docs/manpage.html#-b)

tell curl a file to read cookies from and start the cookie engine, or if it
is not a file it passes on the given string. `-b name=var` works and so does
`-b cookiefile`.

[`-j, --junk-session-cookies`](https://curl.se/docs/manpage.html#-j)

when used in combination with -b, it skips all "session cookies" on load so
as to appear to start a new cookie session.

[`-c, --cookie-jar`](https://curl.se/docs/manpage.html#-c)

tell curl to start the cookie engine and write cookies to the given file
after the request(s)

## Cookies with libcurl

libcurl offers several ways to enable and interface the cookie engine. These
options are the ones provided by the native API. libcurl bindings may offer
access to them using other means.

[`CURLOPT_COOKIE`](https://curl.se/libcurl/c/CURLOPT_COOKIE.html)

Is used when you want to specify the exact contents of a cookie header to
send to the server.

[`CURLOPT_COOKIEFILE`](https://curl.se/libcurl/c/CURLOPT_COOKIEFILE.html)

Tell libcurl to activate the cookie engine, and to read the initial set of
cookies from the given file. Read-only.

[`CURLOPT_COOKIEJAR`](https://curl.se/libcurl/c/CURLOPT_COOKIEJAR.html)

Tell libcurl to activate the cookie engine, and when the easy handle is
closed save all known cookies to the given cookie jar file. Write-only.

[`CURLOPT_COOKIELIST`](https://curl.se/libcurl/c/CURLOPT_COOKIELIST.html)

Provide detailed information about a single cookie to add to the internal
storage of cookies. Pass in the cookie as an HTTP header with all the
details set, or pass in a line from a Netscape cookie file. This option can
also be used to flush the cookies etc.

[`CURLOPT_COOKIESESSION`](https://curl.se/libcurl/c/CURLOPT_COOKIESESSION.html)

Tell libcurl to ignore all cookies it is about to load that are session
cookies.

[`CURLINFO_COOKIELIST`](https://curl.se/libcurl/c/CURLINFO_COOKIELIST.html)

Extract cookie information from the internal cookie storage as a linked
list.

## Cookies with JavaScript

These days a lot of the web is built up by JavaScript. The web browser loads
complete programs that render the page you see. These JavaScript programs
can also set and access cookies.

Since curl and libcurl are plain HTTP clients without any knowledge of or
capability to handle JavaScript, such cookies are not detected or used.

Often, if you want to mimic what a browser does on such websites, you can
record web browser HTTP traffic when using such a site and then repeat the
cookie operations using curl or libcurl.
<!--
Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.

SPDX-License-Identifier: curl
-->

# HTTPS RR

[RFC 9460](https://datatracker.ietf.org/doc/html/rfc9460) documents the HTTPS
DNS Resource Record.

curl features **experimental** support for HTTPS RR.

- The ALPN list from the record is parsed and used
- The ECH field is stored - and used if ECH is enabled in the build
- The port number is not used (Firefox supports it, Chrome does not)
- The target name is not used
- The IP addresses (`Ipv6hints`, `Ipv4hints`) from the HTTPS RR are not used
- It only supports a single HTTPS RR per hostname
- Hostnames without A/AAAA records but *with* HTTPS RR fails
- consider service profiles where the RR provides different addresses for TCP
  vs QUIC etc

`HTTPSRR` is listed as a feature in the `curl -V` output if curl contains
HTTPS RR support. If c-ares is not included in the build, the HTTPS RR support
is limited to DoH.

`asyn-rr` is listed as a feature in the `curl -V` output if c-ares is used for
additional resolves in addition to a "normal" resolve done with the threaded
resolver.

The data extracted from the HTTPS RR is stored in the in-memory DNS cache to
be reused on subsequent uses of the same hostnames.

## limitations

We have decided to work on the HTTPS RR support by following what seems to be
(widely) used, and wait with implementing the details of the record
that do not seem to be deployed. HTTPS RR is a DNS field with many odd corners
and complexities and we might as well avoid them if no one seems to want them.

## build

    ./configure --enable-httpsrr

or

    cmake -DUSE_HTTPSRR=ON

## ALPN

The list of ALPN IDs is parsed but may not be completely respected because of
what the HTTP version preference is set to, which is a problem we are working
on. Also, getting an `HTTP/1.1` ALPN in the HTTPS RR field for an `http://`
transfer should imply switching to HTTPS, HSTS style. Which curl currently
does not.

## DoH

When HTTPS RR is enabled in the curl build, The DoH code asks for an HTTPS
record in addition to the A and AAAA records, and if an HTTPS RR answer is
returned, curl parses it and stores the retrieved information.

## Non-DoH

If DoH is not used for name resolving in an HTTPS RR enabled build, we must
provide the ability using the regular resolver backends. We use the c-ares DNS
library for the HTTPS RR lookup. Version 1.28.0 or greater.

### c-ares

If curl is built to use the c-ares library for name resolves, an HTTPS RR
enabled build makes a request for the HTTPS RR in addition to the regular
lookup.

### Threaded resolver

When built to use the threaded resolver, which is the default, an HTTPS RR
build still needs a c-ares installation provided so that a separate request
for the HTTPS record can be done in parallel to the regular getaddrinfo()
call.

This is done by specifying both c-ares and threaded resolver to configure:

    ./configure --enable-ares=... --enable-threaded-resolver

or to cmake:

    cmake -DENABLE_ARES=ON -DENABLE_THREADED_RESOLVER=ON

Because the HTTPS record is handled separately from the A/AAAA record
retrieval, by a separate library, there is a small risk for discrepancies.

When building curl using the threaded resolver with HTTPS RR support (using
c-ares), the `curl -V` output looks exactly like a c-ares resolver build.

## HTTPS RR Options

Because curl is a low level transfer tool for which users sometimes want
detailed control, we need to offer options to control HTTPS RR use.
<!--
Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.

SPDX-License-Identifier: curl
-->

# Infrastructure in the curl project

Overview of infrastructure we maintain, host and run in the project for the
project.

## git repository

Since 2010, the main curl git repository has been hosted by GitHub, available
at https://github.com/curl/curl.

We also use the issue tracker, pull requests and discussions on GitHub.

curl has an "enterprise account" on GitHub and is an "organization" on the
site.

We accept sponsorship via GitHub Sponsors.

## CI services

For every pull request and git push to the master repository, a number of
build and testing jobs are run on a set of different CI services. The exact
services vary over time. GitHub Actions and AppVeyor are the primary ones
these days.

## Test Clutch

A [Test Clutch](https://github.com/dfandrich/testclutch) instance generates
regular reports on curl CI test results at https://testclutch.curl.se/ as well
as writing comments on curl pull requests whose tests have failed. The jobs
are hosted on a Virtuozzo Application Platform PaaS instance and is managed by
Dan Fandrich. The configuration code is available and managed at
https://github.com/dfandrich/testclutch-curl-web

## Autobuilds

The curl autobuild system is a set of scripts that build and test curl and
send all output logs back to the autobuild server. The results are
continuously collected and visualized on the curl website at
<https://curl.se/dev/builds.html>.

The autobuild system and server is maintained by Daniel Stenberg.

## OSS-Fuzz

Google runs the [OSS-Fuzz](https://google.github.io/oss-fuzz/) project which
also runs fuzzing on curl code, non-stop, in their infrastructure and they
send us emails in the rare instances they actually find something.

OSS-Fuzz notifies those that are members in the "curl team". Any curl
maintainer who wants to is welcome to participate. It requires a Google
account.

## Coverity

We regularly run our code through the [Coverity static code
analyzer](https://scan.coverity.com/) thanks to them offering this service to
us free of charge.

## CodeSonar

[CodeSonar](https://www.adacore.com/codesonar) analyzes the curl
source code daily and emails Daniel Stenberg whenever it finds suspected
problems in the source code. I hope and expect that we can invite other
maintainers to access these reports soon.

## Domain names

The project runs services and website using a few different curl related
domain names, including `curl.se` and `curl.dev`. Daniel Stenberg owns these
domain names.

Until a few years ago, the curl website was present at `curl.haxx.se`. The
`haxx.se` domain is owned by Haxx AB, administered by Daniel Stenberg. The
curl.haxx.se name is meant to keep working and be redirecting to curl.se for
the foreseeable future.

## Websites

The main curl website at `curl.se` is maintained by curl maintainers and the
content is available and managed at https://github.com/curl/curl-www. The site
updates from git and runs make every 20 minutes. Any change pushed to git can
thus take up to 20 minutes until it takes effect on the origin server.

The content on `curl.dev` is available and managed at
https://github.com/curl/curl.dev/

The content on `everything.curl.dev` is available and managed at
https://github.com/curl/everything-curl/

The machine hosting the website contents for these three sites is owned by
Haxx AB and is primarily managed by Daniel Stenberg (co-owner of the Haxx
company). The machine is physically located in Sweden.

curl release tarballs are hosted on https://curl.se/download.html. They are
uploaded there at release-time by the release manager.

curl-for-win downloads are hosted on https://curl.se/windows/ and are uploaded
to the server by Viktor Szakats.

curl-for-QNX downloads are hosted on <https://curl.se/qnx/> and are uploaded
to the server by Daniel Stenberg.

Daily release tarball-like snapshots are generated automatically and are
provided for download at <https://curl.se/snapshots/>.

CA certificate bundles are extracted from the Firefox source code, hosted by
Mozilla and converted to PEM file format and is offered for download. The
conversion checks for updates daily. The bundle is provided for download at
<https://curl.se/docs/caextract.html>.

There is an automated "download check bot" that runs twice daily to scan for
available curl downloads to populate the curl download page appropriately with
the correct updated information. The bot uses URLs and patterns for all
download packages and is maintained in a database, maintained by Daniel
Stenberg and Dan Fandrich.

The TLS certificate for the origin curl web server is automatically updated
from Let's Encrypt.

## CDN

Fastly runs the Content Delivery Network (CDN) that fronts all the curl
websites. The CDN caches content that it gets from the origin server.
Recently, roughly 99.99% of web requests are satisfied by the CDN without
having to reach the origin.

The CDN caches different content at different lengths depending on the
content-type. The caching thus adds to the time for a change to have an effect
on the site from the moment it gets pushed to the git repository.

Using this setup, we provide four IPv4 addresses and eight IPv6 addresses for
anycast access to the site. Should be snappy from virtually everywhere across
the globe.

The CDN servers support HTTP/1, HTTP/2 and HTTP/3. They set HSTS for a year.
The `http://` version of the site redirects to `https://`.

Fastly manages the TLS certificates from Let's Encrypt for the servers they
run on the behalf of curl.

## Containers

The curl project offer container builds of curl. The source repository for
them is located at <https://github.com/curl/curl-container>.

Container images are hosted at <https://quay.io/repository/curl/curl> and
<https://hub.docker.com/r/curlimages/curl>

## DNS

The primary domain name, `curl.se` is managed by Kirei and is offered over
fault-tolerant anycast servers. High availability and fast access for
everyone.

The actual physical DNS files and origin bind instance is managed by Daniel
Stenberg.

## Mailing lists

The curl related mailing lists are hosted by Haxx AB on `lists.haxx.se` and
are maintained by Daniel Stenberg. This includes the mailman2 and Postfix
instances used for this.

## Email

We use a few rare additional curl related email aliases in the curl domains.
They go through the mail server `mail.haxx.se` maintained by Daniel Stenberg

## Open Collective

We use [Open Collective](https://opencollective.com/curl) as our "fiscal
host". All money sent to and received by the curl project is managed by Open
Collective.

## Merchandise

We have stickers, coffee mugs and coasters. They are managed by Daniel who
sits on the inventory. The best way to get your hands on curl merchandise is
to attend events where Daniel is physically.

## Chat

Some curl developers, maintainers, users and enthusiasts use IRC for real-time
chat about curl and related topics. This done in the `#curl` channel on the
`libra.chat` IRC network. **Daniel Stenberg** (`bagder`) is registered owner
of the channel. We do not run any IRC servers or services ourselves.

`curlbot` is a service in the channel that shows details about GitHub issues
and pull requests when publicly mentioned using #[number]. The bot is run by
user `TheAssassin`.

There is a Matrix bridge to the IRC channel called `matrix.curl.se`. The
bridge is setup and run by **Sergio Durigan Junior** and **Daniel Stenberg**.

[curl online chat documentation](https://curl.se/docs/irc.html)
<!--
Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.

SPDX-License-Identifier: curl
-->

# Building with CMake

This document describes how to configure, build and install curl and libcurl
from source code using the CMake build tool. To build with CMake, you of
course first have to install CMake. The minimum required version of CMake is
specified in the file `CMakeLists.txt` found in the top of the curl source
tree. Once the correct version of CMake is installed you can follow the
instructions below for the platform you are building on.

CMake builds can be configured either from the command line, or from one of
CMake's GUIs.

# Configuring

A CMake configuration of curl is similar to the autotools build of curl.
It consists of the following steps after you have unpacked the source.

We recommend building with CMake on Windows. For instructions on migrating
from the `projects/Windows` Visual Studio solution files, see
[this section](#migrating-from-visual-studio-ide-project-files).

## Using `cmake`

You can configure for in source tree builds or for a build tree
that is apart from the source tree.

- Build in the source tree.

      $ cmake -B .

- Build in a separate directory (parallel to the curl source tree in this
  example). The build directory is created for you. This is recommended over
  building in the source tree to separate source and build artifacts.

      $ cmake -B ../curl-build

For the full list of CMake build configuration variables see
[the corresponding section](#cmake-build-options).

### Build system generator selection

You can override CMake's default by using `-G <generator-name>`. For example
on Windows with multiple build systems if you have mingw-w64 then you could use
`-G "MinGW Makefiles"`.
[List of generator names](https://cmake.org/cmake/help/latest/manual/cmake-generators.7.html).

## Using `ccmake`

CMake comes with a curses based interface called `ccmake`. To run `ccmake`
on a curl use the instructions for the command line cmake, but substitute
`ccmake` for `cmake`.

This brings up a curses interface with instructions on the bottom of the
screen. You can press the "c" key to configure the project, and the "g" key to
generate the project. After the project is generated, you can run make.

## Using `cmake-gui`

CMake also comes with a Qt based GUI called `cmake-gui`. To configure with
`cmake-gui`, you run `cmake-gui` and follow these steps:

1. Fill in the "Where is the source code" combo box with the path to
   the curl source tree.
2. Fill in the "Where to build the binaries" combo box with the path to
   the directory for your build tree, ideally this should not be the same
   as the source tree, but a parallel directory called curl-build or
   something similar.
3. Once the source and binary directories are specified, press the
   "Configure" button.
4. Select the native build tool that you want to use.
5. At this point you can change any of the options presented in the GUI.
   Once you have selected all the options you want, click the "Generate"
   button.

# Building

Build (you have to specify the build directory).

    $ cmake --build ../curl-build

## Static builds

The CMake build setup is primarily done to work with shared/dynamic third
party dependencies. When linking with shared libraries, the dependency "chain"
is handled automatically by the library loader - on all modern systems.

If you instead link with a static library, you need to provide all the
dependency libraries already at the link command line.

Figuring out all the dependency libraries for a given library is hard, as it
might involve figuring out the dependencies of the dependencies and they vary
between platforms and can change between versions.

When using static dependencies, the build scripts mostly assume that you, the
user, provide all the necessary additional dependency libraries as additional
arguments in the build.

Building statically is not for the faint of heart.

# Testing

(The test suite does not yet work with the cmake build)

# Installing

Install to default location (you have to specify the build directory).

    $ cmake --install ../curl-build

Do not use `--prefix` to change the installation prefix as the output produced
by the `curl-config` script is determined at CMake configure time. If you want
to set a custom install prefix for curl, set
[`CMAKE_INSTALL_PREFIX`](https://cmake.org/cmake/help/latest/variable/CMAKE_INSTALL_PREFIX.html)
when configuring the CMake build.

# CMake usage

This section describes how to locate and use curl/libcurl from CMake-based
projects.

## Using `find_package`

To locate libcurl from CMake, one can use the standard
[`find_package`](https://cmake.org/cmake/help/latest/command/find_package.html)
command in the typical fashion:

```cmake
find_package(CURL 8.12.0 REQUIRED)  # FATAL_ERROR if CURL is not found
```

This invokes the CMake-provided
[FindCURL](https://cmake.org/cmake/help/latest/module/FindCURL.html) find module,
which first performs a search using the `find_package`
[config mode](https://cmake.org/cmake/help/latest/command/find_package.html#config-mode-search-procedure).
This is supported by the `CURLConfig.cmake` CMake config script which is
available if the given CURL was built and installed using CMake.

### Detecting CURL features/protocols

Since version 8.12.0, `CURLConfig.cmake` publishes the supported CURL features
and protocols (see [release notes](https://curl.se/ch/8.12.0.html)). These can
be specified using the `find_package` keywords `COMPONENTS` and
`OPTIONAL_COMPONENTS`, with protocols in all caps, e.g. `HTTPS`, `LDAP`, while
features should be in their original sentence case, e.g. `AsynchDNS`,
`UnixSockets`. If any of the `COMPONENTS` are missing, then CURL is considered
as *not* found.

Here is an example of using `COMPONENTS` and `OPTIONAL_COMPONENTS` in
`find_package` with CURL:

```cmake
# CURL_FOUND is FALSE if no HTTPS but brotli and zstd can be missing
find_package(CURL 8.12.0 COMPONENTS HTTPS OPTIONAL_COMPONENTS brotli zstd)
```

One can also check the defined `CURL_SUPPORTS_<feature-or-protocol>` variables
if a particular feature/protocol is supported. For example:

```cmake
# check HTTPS
if(CURL_SUPPORTS_HTTPS)
  message(STATUS "CURL supports HTTPS")
else()
  message(STATUS "CURL does NOT support HTTPS")
endif()
```

### Linking against libcurl

To link a CMake target against libcurl one can use
[`target_link_libraries`](https://cmake.org/cmake/help/latest/command/target_link_libraries.html)
as usual:

```cmake
target_link_libraries(my_target PRIVATE CURL::libcurl)
```

# CMake build options

- `BUILD_CURL_EXE`:                         Build curl executable. Default: `ON`
- `BUILD_EXAMPLES`:                         Build libcurl examples. Default: `ON`
- `BUILD_LIBCURL_DOCS`:                     Build libcurl man pages. Default: `ON`
- `BUILD_MISC_DOCS`:                        Build misc man pages (e.g. `curl-config` and `mk-ca-bundle`). Default: `ON`
- `BUILD_SHARED_LIBS`:                      Build shared libraries. Default: `ON` (if target platform supports shared libs, otherwise `OFF`)
- `BUILD_STATIC_CURL`:                      Build curl executable with static libcurl. Default: `OFF` (turns to `ON`, when building static libcurl only)
- `BUILD_STATIC_LIBS`:                      Build static libraries. Default: `OFF` (turns to `ON` if `BUILD_SHARED_LIBS` is `OFF`)
- `BUILD_TESTING`:                          Build tests. Default: `ON`
- `CURL_BUILD_EVERYTHING`:                  Build optional build targets (examples, tests) by default. Default: `OFF`
                                            Set `QUICK` to build examples quickly with the `curl-examples-build` target (for build tests).
                                            Set `NOEXAMPLES` to not build examples.
- `CURL_CLANG_TIDY`:                        Run the build through `clang-tidy`. Default: `OFF`
                                            If enabled, it implies `CURL_DISABLE_TYPECHECK=ON` and force-disables unity mode
                                            for libcurl and the curl tool.
- `CURL_CLANG_TIDYFLAGS`:                   Custom options to pass to `clang-tidy`. Default: (empty)
- `CURL_CODE_COVERAGE`:                     Enable code coverage build options. Default: `OFF`
- `CURL_COMPLETION_FISH`:                   Install fish completions. Default: `OFF`
- `CURL_COMPLETION_FISH_DIR`:               Custom fish completion install directory.
- `CURL_COMPLETION_ZSH`:                    Install zsh completions. Default: `OFF`
- `CURL_COMPLETION_ZSH_DIR`:                Custom zsh completion install directory.
- `CURL_DEBUG_GLOBAL_MEM`:                  Debug `curl_global_init_mem`. Default: `OFF`
- `CURL_DEFAULT_SSL_BACKEND`:               Override default TLS backend in MultiSSL builds.
                                            Accepted values in order of default priority:
                                            `wolfssl`, `gnutls`, `mbedtls`, `openssl`, `schannel`, `rustls`
- `CURL_DROP_UNUSED`:                       Drop unused code and data from built binaries. Default: `OFF`
- `CURL_ENABLE_EXPORT_TARGET`:              Enable CMake export target. Default: `ON`
- `CURL_GCC_ANALYZER`:                      Enable GCC `--analyzer` option. Default: `OFF`
- `CURL_HIDDEN_SYMBOLS`:                    Hide libcurl internal symbols (=hide all symbols that are not officially external). Default: `ON`
- `CURL_LIBCURL_SOVERSION`:                 Enable libcurl SOVERSION. Default: `ON` for supported platforms
- `CURL_LIBCURL_VERSIONED_SYMBOLS`:         Enable libcurl versioned symbols. Default: `OFF`
- `CURL_LIBCURL_VERSIONED_SYMBOLS_PREFIX`:  Override default versioned symbol prefix. Default: `<TLS-BACKEND>_` or `MULTISSL_`
- `CURL_LINT`:                              Run lint checks while building. Default: `OFF`
- `CURL_LTO`:                               Enable compiler Link Time Optimizations. Default: `OFF`
- `CURL_PATCHSTAMP`:                        Set security patch string for `curl -V`/`curl --version` output.
- `CURL_STATIC_CRT`:                        Build libcurl with static CRT with MSVC (`/MT`) (requires UCRT, static libcurl or no curl executable). Default: `OFF`
- `CURL_TARGET_WINDOWS_VERSION`:            Minimum target Windows version as hex string, e.g. `0x0a00` for Windows 10.
- `CURL_WERROR`:                            Turn compiler warnings into errors. Default: `OFF`
- `ENABLE_CURL_MANUAL`:                     Build the man page for curl and enable its `-M`/`--manual` option. Default: `ON`
- `ENABLE_DEBUG`:                           Enable curl debug features (for developing curl). Default: `OFF`
                                            This also requires Debug configuration enabled/selected at the same time,
                                            via `CMAKE_BUILD_TYPE=Debug`, or `--config Debug` for multi-config generators.
- `IMPORT_LIB_SUFFIX`:                      Import library suffix. Default: `_imp` for MSVC-like toolchains, otherwise empty.
- `LIBCURL_OUTPUT_NAME`:                    Basename of the curl library. Default: `libcurl`
- `PICKY_COMPILER`:                         Enable picky compiler options. Default: `ON`
- `SHARE_LIB_OBJECT`:                       Build shared and static libcurl in a single pass. Default: `ON` for Windows
- `STATIC_LIB_SUFFIX`:                      Static library suffix. Default: (empty)

## Root CA options

- `CURL_CA_BUNDLE`:                         Absolute path to the CA bundle. Set `none` to disable or `auto` for auto-detection. Default: `auto`
- `CURL_CA_EMBED`:                          Absolute path to the CA bundle to embed in the curl tool. Default: (disabled)
- `CURL_CA_FALLBACK`:                       Use built-in CA store of OpenSSL. Default: `OFF`
- `CURL_CA_NATIVE`:                         Use native CA store. Default: `OFF`
                                            Supported by GnuTLS, OpenSSL (including forks) on Windows, wolfSSL.
- `CURL_CA_PATH`:                           Absolute path to a directory containing CA certificates stored individually.
                                            Set `none` to disable or `auto` for auto-detection. Default: `auto`
- `CURL_CA_SEARCH_SAFE`:                    Enable safe CA bundle search (within the curl tool directory) on Windows. Default: `OFF`
- `USE_APPLE_SECTRUST`:                     Use Apple OS-native certificate verification. Default: `OFF`

## Enabling features

- `CURL_ENABLE_APPLE_FAST_UDP`:             Use Apple fast UDP (experimental). Default: `OFF`
- `CURL_ENABLE_NTLM`:                       Enable NTLM support. Default: `OFF`
- `CURL_ENABLE_SMB`:                        Enable SMB. Default: `OFF`
- `CURL_ENABLE_SSL`:                        Enable SSL support. Default: `ON`
- `CURL_WINDOWS_SSPI`:                      Enable SSPI on Windows. Default: =`CURL_USE_SCHANNEL`
- `ENABLE_IPV6`:                            Enable IPv6 support. Default: `ON` if target supports IPv6.
- `ENABLE_THREADED_RESOLVER`:               Enable threaded DNS lookup. Default: `ON` if c-ares is not enabled and target supports threading.
- `ENABLE_UNICODE`:                         Use the Unicode version of the Windows API functions. Default: `OFF`
- `ENABLE_UNIX_SOCKETS`:                    Enable Unix domain sockets support. Default: `ON`
- `USE_APPLE_IDN`:                          Use Apple built-in IDN support. Default: `OFF`
- `USE_ECH`:                                Enable ECH support (experimental). Default: `OFF`
- `USE_HTTPSRR`:                            Enable HTTPS RR support (experimental). Default: `OFF`
- `USE_PROXY_HTTP3`:                        Enable HTTP/3 proxy support (experimental). Default: `OFF`
- `USE_SSLS_EXPORT`:                        Enable SSL session import/export (experimental). Default: `OFF`
- `USE_WIN32_IDN`:                          Use WinIDN for IDN support. Default: `OFF`
- `USE_WIN32_LDAP`:                         Use Windows LDAP implementation. Default: `ON`

## Disabling features

- `CURL_DISABLE_ALTSVC`:                    Disable alt-svc support. Default: `OFF`
- `CURL_DISABLE_AWS`:                       Disable **aws-sigv4**. Default: `OFF`
- `CURL_DISABLE_BASIC_AUTH`:                Disable Basic authentication. Default: `OFF`
- `CURL_DISABLE_BEARER_AUTH`:               Disable Bearer authentication. Default: `OFF`
- `CURL_DISABLE_BINDLOCAL`:                 Disable local binding support. Default: `OFF`
- `CURL_DISABLE_CA_SEARCH`:                 Disable unsafe CA bundle search in PATH on Windows. Default: `OFF` (turns to `ON`, when `CURL_CA_NATIVE=ON`)
- `CURL_DISABLE_COOKIES`:                   Disable cookies support. Default: `OFF`
- `CURL_DISABLE_DICT`:                      Disable DICT. Default: `OFF`
- `CURL_DISABLE_DIGEST_AUTH`:               Disable Digest authentication. Default: `OFF`
- `CURL_DISABLE_DOH`:                       Disable DNS-over-HTTPS. Default: `OFF`
- `CURL_DISABLE_FILE`:                      Disable FILE. Default: `OFF`
- `CURL_DISABLE_FORM_API`:                  Disable **form-api**. Default: =`CURL_DISABLE_MIME`
- `CURL_DISABLE_FTP`:                       Disable FTP. Default: `OFF`
- `CURL_DISABLE_GETOPTIONS`:                Disable `curl_easy_options` API for existing options to `curl_easy_setopt`. Default: `OFF`
- `CURL_DISABLE_GOPHER`:                    Disable Gopher. Default: `OFF`
- `CURL_DISABLE_HEADERS_API`:               Disable **headers-api** support. Default: `OFF`
- `CURL_DISABLE_HSTS`:                      Disable HSTS support. Default: `OFF`
- `CURL_DISABLE_HTTP`:                      Disable HTTP. Default: `OFF`
- `CURL_DISABLE_HTTP_AUTH`:                 Disable all HTTP authentication methods. Default: `OFF`
- `CURL_DISABLE_HTTPSIG`:                   Disable HTTP Message Signatures (RFC 9421) (experimental). Default: `ON`
- `CURL_DISABLE_IMAP`:                      Disable IMAP. Default: `OFF`
- `CURL_DISABLE_INSTALL`:                   Disable installation targets. Default: `OFF`
- `CURL_DISABLE_IPFS`:                      Disable IPFS. Default: `OFF`
- `CURL_DISABLE_KERBEROS_AUTH`:             Disable Kerberos authentication. Default: `OFF`
- `CURL_DISABLE_LDAP`:                      Disable LDAP. Default: `OFF`
- `CURL_DISABLE_LDAPS`:                     Disable LDAPS. Default: =`CURL_DISABLE_LDAP`
- `CURL_DISABLE_LIBCURL_OPTION`:            Disable `--libcurl` option from the curl tool. Default: `OFF`
- `CURL_DISABLE_MIME`:                      Disable MIME support. Default: `OFF`
- `CURL_DISABLE_MQTT`:                      Disable MQTT. Default: `OFF`
- `CURL_DISABLE_NEGOTIATE_AUTH`:            Disable negotiate authentication. Default: `OFF`
- `CURL_DISABLE_NETRC`:                     Disable netrc parser. Default: `OFF`
- `CURL_DISABLE_OPENSSL_AUTO_LOAD_CONFIG`:  Disable automatic loading of OpenSSL configuration. Default: `OFF`
- `CURL_DISABLE_PARSEDATE`:                 Disable date parsing. Default: `OFF`
- `CURL_DISABLE_POP3`:                      Disable POP3. Default: `OFF`
- `CURL_DISABLE_PROGRESS_METER`:            Disable built-in progress meter. Default: `OFF`
- `CURL_DISABLE_PROXY`:                     Disable proxy support. Default: `OFF`
- `CURL_DISABLE_RTSP`:                      Disable RTSP. Default: `OFF`
- `CURL_DISABLE_SHA512_256`:                Disable SHA-512/256 hash algorithm. Default: `OFF`
- `CURL_DISABLE_SHUFFLE_DNS`:               Disable shuffle DNS feature. Default: `OFF`
- `CURL_DISABLE_SMTP`:                      Disable SMTP. Default: `OFF`
- `CURL_DISABLE_SOCKETPAIR`:                Disable use of socketpair for curl_multi_poll(). Default: `OFF`
- `CURL_DISABLE_TELNET`:                    Disable Telnet. Default: `OFF`
- `CURL_DISABLE_TFTP`:                      Disable TFTP. Default: `OFF`
- `CURL_DISABLE_TYPECHECK`:                 Disable curl_easy_setopt()/curl_easy_getinfo() type checking. Default: `OFF`
- `CURL_DISABLE_VERBOSE_STRINGS`:           Disable verbose strings. Default: `OFF`
- `CURL_DISABLE_WEBSOCKETS`:                Disable WebSocket. Default: `OFF`
- `HTTP_ONLY`:                              Disable all protocols except HTTP (This overrides all `CURL_DISABLE_*` options). Default: `OFF`

## Environment

- `CI`:                                     Assume running under CI if set.
- `CURL_BUILDINFO`:                         Print `buildinfo.txt` if set.
- `CURL_CI`:                                Assume running under CI if set.

## Environment (via CMake)

- `CC`:                                     Set C compiler. Alternative to `CMAKE_C_COMPILER` option.
- `CFLAGS`:                                 Pass custom C compiler flags. Alternative to `CMAKE_C_FLAGS` option.
- `CMAKE_GENERATOR`:                        Alternative to `-G` command-line option.
- `DESTDIR`:                                Set install destination directory.
- `LDFLAGS`:                                Pass custom linker flags.

Details via CMake
[envvars](https://cmake.org/cmake/help/latest/manual/cmake-env-variables.7.html).

## CMake options

- `CMAKE_BUILD_TYPE`:                       (see CMake)
- `CMAKE_DEBUG_POSTFIX`:                    Default: `-d`
- `CMAKE_IMPORT_LIBRARY_SUFFIX`             (see CMake)
- `CMAKE_INSTALL_BINDIR`                    (see CMake)
- `CMAKE_INSTALL_INCLUDEDIR`                (see CMake)
- `CMAKE_INSTALL_LIBDIR`                    (see CMake)
- `CMAKE_INSTALL_PREFIX`                    (see CMake) (in CMake 3.29+ also supported as environment)
- `CMAKE_STATIC_LIBRARY_SUFFIX`             (see CMake)
- `CMAKE_UNITY_BUILD_BATCH_SIZE`:           Set the number of sources in a "unity" unit. Default: `0` (all)
- `CMAKE_UNITY_BUILD`:                      Enable "unity" (aka "jumbo") builds. Default: `OFF`

Details via CMake
[variables](https://cmake.org/cmake/help/latest/manual/cmake-variables.7.html) and
[install directories](https://cmake.org/cmake/help/latest/module/GNUInstallDirs.html).

## Dependencies

- `CURL_BROTLI`:                            Use brotli (`ON`, `OFF` or `AUTO`). Default: `AUTO`
- `CURL_USE_CMAKECONFIG`:                   Enable detecting dependencies via CMake Config.
                                            Default: `ON` for MSVC (except under vcpkg), if not cross-compiling. (experimental)
- `CURL_GSS_FLAVOR`:                        Set preferred GSSAPI implementation (`Apple`). Default: MIT, then GNU (experimental)
- `CURL_USE_GNUTLS`:                        Enable GnuTLS for SSL/TLS. Default: `OFF`
- `CURL_USE_GSASL`:                         Use libgsasl. Default: `OFF`
- `CURL_USE_GSSAPI`:                        Use GSSAPI implementation. Default: `OFF`
- `CURL_USE_LIBBACKTRACE`:                  Use [libbacktrace](https://github.com/ianlancetaylor/libbacktrace).
                                            Requires debug-enabled build and DWARF debug information. Default: `OFF`
- `CURL_USE_LIBPSL`:                        Use libpsl. Default: `ON`
- `CURL_USE_LIBSSH2`:                       Use libssh2. Default: `ON`
- `CURL_USE_LIBSSH`:                        Use libssh. Default: `OFF`
- `CURL_USE_LIBUV`:                         Use libuv for event-based tests. Default: `OFF`
- `CURL_USE_MBEDTLS`:                       Enable mbedTLS for SSL/TLS. Default: `OFF`
- `CURL_USE_OPENSSL`:                       Enable OpenSSL for SSL/TLS. Default: `ON` if no other TLS backend was enabled.
- `CURL_USE_PKGCONFIG`:                     Enable `pkg-config` to detect dependencies.
                                            Default: `ON` for Unix (except Android, Apple devices), vcpkg, MinGW if not cross-compiling.
- `CURL_USE_RUSTLS`:                        Enable Rustls for SSL/TLS (experimental). Default: `OFF`
- `CURL_USE_SCHANNEL`:                      Enable Windows native SSL/TLS (Schannel). Default: `OFF`
- `CURL_USE_WOLFSSL`:                       Enable wolfSSL for SSL/TLS. Default: `OFF`
- `CURL_ZLIB`:                              Use zlib (`ON`, `OFF` or `AUTO`). Default: `AUTO`
- `CURL_ZSTD`:                              Use zstd (`ON`, `OFF` or `AUTO`). Default: `AUTO`
- `ENABLE_ARES`:                            Enable c-ares support. Default: `OFF`
- `USE_LIBIDN2`:                            Use libidn2 for IDN support. Default: `ON`
- `USE_NGHTTP2`:                            Use nghttp2 library. Default: `ON`
- `USE_NGTCP2`:                             Use ngtcp2 and nghttp3 libraries for HTTP/3 support. Default: `OFF`
- `USE_QUICHE`:                             Use quiche library for HTTP/3 support (experimental). Default: `OFF`

## Dependency options (via CMake)

- `OPENSSL_ROOT_DIR`:                       Absolute path to the installation root of OpenSSL (and forks).
- `OPENSSL_INCLUDE_DIR`:                    Absolute path to OpenSSL include directory.
- `OPENSSL_SSL_LIBRARY`:                    Absolute path to `ssl` library.
                                            With MSVC, CMake uses variables `SSL_EAY_DEBUG`/`SSL_EAY_RELEASE` instead.
- `OPENSSL_CRYPTO_LIBRARY`:                 Absolute path to `crypto` library.
                                            With MSVC, CMake uses variables `LIB_EAY_DEBUG`/`LIB_EAY_RELEASE` instead.
- `OPENSSL_USE_STATIC_LIBS`:                Look for static OpenSSL libraries.
- `ZLIB_INCLUDE_DIR`:                       Absolute path to zlib include directory.
- `ZLIB_LIBRARY`:                           Absolute path to `zlib` library.
- `ZLIB_ROOT`:                              Absolute path to the installation root of zlib.
- `ZLIB_USE_STATIC_LIBS`:                   Look for static `zlib` library (requires CMake 3.24+).
- `<PackageName>_DIR`:                      Absolute path to `<PackageName>` CMake Config directory where `*.cmake` files reside.
                                            Used when `CURL_USE_CMAKECONFIG` is enabled.
                                            `<PackageName>` may be:
                                            `c-ares`, `Libssh2`, `MbedTLS`, `NGHTTP2`, `NGHTTP3`,
                                            `NGTCP2` for 1.19.0+ (with non-fork OpenSSL only),
                                            `wolfssl` for 5.2.1+, `Zstd` for 1.4.5+.

## Dependency options (tools)

- `CLANG_TIDY`:                             Absolute path to `clang-tidy` tool used with `CURL_CLANG_TIDY=ON`. Default: search for `clang-tidy`
- `PERL_EXECUTABLE`:                        Absolute path to Perl binary used throughout the build and tests. Default: auto-detect

## Dependency options (libraries)

- `AMISSL_INCLUDE_DIR`:                     Absolute path to AmiSSL include directory.
- `AMISSL_STUBS_LIBRARY`:                   Absolute path to `amisslstubs` library.
- `AMISSL_AUTO_LIBRARY`:                    Absolute path to `amisslauto` library.
- `BORINGSSL_VERSION`:                      Set BoringSSL version for `curl -V`/`curl --version` output.
- `BROTLI_INCLUDE_DIR`:                     Absolute path to brotli include directory.
- `BROTLICOMMON_LIBRARY`:                   Absolute path to `brotlicommon` library.
- `BROTLIDEC_LIBRARY`:                      Absolute path to `brotlidec` library.
- `BROTLI_USE_STATIC_LIBS`:                 Configure for static brotli libraries. (experimental)
- `CARES_INCLUDE_DIR`:                      Absolute path to c-ares include directory.
- `CARES_LIBRARY`:                          Absolute path to `cares` library.
- `CARES_USE_STATIC_LIBS`:                  Configure for static c-ares libraries. (experimental)
- `DL_LIBRARY`:                             Absolute path to `dl` library. (for Rustls)
- `GNUTLS_INCLUDE_DIR`:                     Absolute path to GnuTLS include directory.
- `GNUTLS_LIBRARY`:                         Absolute path to `gnutls` library.
- `GSS_ROOT_DIR`:                           Absolute path to the installation root of GSS. (also supported as environment)
- `LDAP_INCLUDE_DIR`:                       Absolute path to LDAP include directory.
- `LDAP_LIBRARY`:                           Absolute path to `ldap` library.
- `LDAP_LBER_LIBRARY`:                      Absolute path to `lber` library.
- `LIBBACKTRACE_INCLUDE_DIR`:               Absolute path to libbacktrace include directory (https://github.com/ianlancetaylor/libbacktrace).
- `LIBBACKTRACE_LIBRARY`:                   Absolute path to `libbacktrace` library.
- `LIBGSASL_INCLUDE_DIR`:                   Absolute path to libgsasl include directory.
- `LIBGSASL_LIBRARY`:                       Absolute path to `libgsasl` library.
- `LIBIDN2_INCLUDE_DIR`:                    Absolute path to libidn2 include directory.
- `LIBIDN2_LIBRARY`:                        Absolute path to `libidn2` library.
- `LIBPSL_INCLUDE_DIR`:                     Absolute path to libpsl include directory.
- `LIBPSL_LIBRARY`:                         Absolute path to `libpsl` library.
- `LIBSSH_INCLUDE_DIR`:                     Absolute path to libssh include directory.
- `LIBSSH_LIBRARY`:                         Absolute path to `libssh` library.
- `LIBSSH_USE_STATIC_LIBS`:                 Configure for static libssh libraries. (experimental)
- `LIBSSH2_INCLUDE_DIR`:                    Absolute path to libssh2 include directory.
- `LIBSSH2_LIBRARY`:                        Absolute path to `libssh2` library.
- `LIBSSH2_USE_STATIC_LIBS`:                Configure for static libssh2 libraries. (experimental)
- `LIBUV_INCLUDE_DIR`:                      Absolute path to libuv include directory.
- `LIBUV_LIBRARY`:                          Absolute path to `libuv` library.
- `MATH_LIBRARY`:                           Absolute path to `m` library. (for Rustls, wolfSSL)
- `MBEDTLS_INCLUDE_DIR`:                    Absolute path to mbedTLS include directory.
- `MBEDTLS_LIBRARY`:                        Absolute path to `mbedtls` library.
- `MBEDX509_LIBRARY`:                       Absolute path to `mbedx509` library.
- `MBEDCRYPTO_LIBRARY`:                     Absolute path to `mbedcrypto` library.
- `MBEDTLS_USE_STATIC_LIBS`:                Configure for static mbedTLS libraries. (experimental)
- `NGHTTP2_INCLUDE_DIR`:                    Absolute path to nghttp2 include directory.
- `NGHTTP2_LIBRARY`:                        Absolute path to `nghttp2` library.
- `NGHTTP2_USE_STATIC_LIBS`:                Configure for static nghttp2 libraries. (experimental)
- `NGHTTP3_INCLUDE_DIR`:                    Absolute path to nghttp3 include directory.
- `NGHTTP3_LIBRARY`:                        Absolute path to `nghttp3` library.
- `NGHTTP3_USE_STATIC_LIBS`:                Configure for static nghttp3 libraries. (experimental)
- `NGTCP2_INCLUDE_DIR`:                     Absolute path to ngtcp2 include directory.
- `NGTCP2_LIBRARY`:                         Absolute path to `ngtcp2` library.
- `NGTCP2_CRYPTO_BORINGSSL_LIBRARY`:        Absolute path to `ngtcp2_crypto_boringssl` library. (also for AWS-LC)
- `NGTCP2_CRYPTO_GNUTLS_LIBRARY`:           Absolute path to `ngtcp2_crypto_gnutls` library.
- `NGTCP2_CRYPTO_LIBRESSL_LIBRARY`:         Absolute path to `ngtcp2_crypto_libressl` library. (requires ngtcp2 1.15.0+)
- `NGTCP2_CRYPTO_OSSL_LIBRARY`:             Absolute path to `ngtcp2_crypto_ossl` library.
- `NGTCP2_CRYPTO_QUICTLS_LIBRARY`:          Absolute path to `ngtcp2_crypto_quictls` library. (also for LibreSSL with ngtcp2 <1.15.0)
- `NGTCP2_CRYPTO_WOLFSSL_LIBRARY`:          Absolute path to `ngtcp2_crypto_wolfssl` library.
- `NGTCP2_USE_STATIC_LIBS`:                 Configure for static ngtcp2 libraries. (experimental)
- `NETTLE_INCLUDE_DIR`:                     Absolute path to nettle include directory.
- `NETTLE_HOGWEED_LIBRARY`:                 Absolute path to `hogweed` library.
- `NETTLE_LIBRARY`:                         Absolute path to `nettle` library.
- `PTHREAD_LIBRARY`:                        Absolute path to `pthread` library. (for Rustls)
- `QUICHE_INCLUDE_DIR`:                     Absolute path to quiche include directory.
- `QUICHE_LIBRARY`:                         Absolute path to `quiche` library.
- `RUSTLS_INCLUDE_DIR`:                     Absolute path to Rustls include directory.
- `RUSTLS_LIBRARY`:                         Absolute path to `rustls` library.
- `WATT_ROOT`:                              Absolute path to the installation root of Watt-32.
- `WOLFSSL_INCLUDE_DIR`:                    Absolute path to wolfSSL include directory.
- `WOLFSSL_LIBRARY`:                        Absolute path to `wolfssl` library.
- `ZSTD_INCLUDE_DIR`:                       Absolute path to zstd include directory.
- `ZSTD_LIBRARY`:                           Absolute path to `zstd` library.
- `ZSTD_USE_STATIC_LIBS`:                   Configure for static zstd libraries. (experimental)

Examples:

- `-DLIBPSL_INCLUDE_DIR=/path/to/libpsl/include`,
  which directory contains `libpsl.h`.
  No ending slash or backslash is necessary.

- `-DNGHTTP3_INCLUDE_DIR=/path/to/libnghttp3/include`,
  which directory contains an `nghttp3` subdirectory with `.h` files in it.

- `-DLIBPSL_LIBRARY=/path/to/libpsl/lib/libpsl.a`
  Always a single library, with its complete filename, as-is on the file system.

- `-DOPENSSL_ROOT_DIR=/path/to/openssl`,
  which directory (typically) contains `include` and `lib` subdirectories.
  No ending slash or backslash is necessary.

## Dependency options (Apple frameworks)

- `COREFOUNDATION_FRAMEWORK`:               Absolute path to `CoreFoundation` framework. (for IPv6 non-c-ares, SecTrust, wolfSSL)
- `CORESERVICES_FRAMEWORK`:                 Absolute path to `CoreServices` framework. (for IPv6 non-c-ares, SecTrust)
- `FOUNDATION_FRAMEWORK`:                   Absolute path to `Foundation` framework. (for Rustls)
- `SECURITY_FRAMEWORK`:                     Absolute path to `Security` framework. (for Rustls, SecTrust, wolfSSL)
- `SYSTEMCONFIGURATION_FRAMEWORK`:          Absolute path to `SystemConfiguration` framework. (for IPv6 non-c-ares)

## Test tools

- `APXS`:                                   Absolute path. Default: search for `apxs`
- `CADDY`:                                  Absolute path. Default: search for `caddy`
- `H2O`:                                    Absolute path. Default: search for `h2o`
- `HTTPD_NGHTTPX`:                          Absolute path. Default: search for `nghttpx`
- `HTTPD`:                                  Absolute path. Default: search for `apache2`
- `DANTED`:                                 Absolute path. Default: search for `danted`
- `TEST_NGHTTPX`:                           Absolute path. Default: search for `nghttpx`
- `VSFTPD`:                                 Absolute path. Default: search for `vsftpd`
- `SSHD`:                                   Absolute path. Default: search for `sshd`
- `SFTPD`:                                  Absolute path. Default: search for `sftp-server`

## Feature detection variables

By default the curl CMake build script detects the version of some dependencies
using `check_symbol_exists()`. Those checks do not work in the case that both
CURL and its dependency are included as sub-projects in a larger build using
`FetchContent`. To support that case, additional variables may be defined by
the parent project, ideally in the "extra" find package redirect file:
<https://cmake.org/cmake/help/latest/module/FetchContent.html#integrating-with-find-package>

Available variables:

- `HAVE_DES_ECB_ENCRYPT`:                   `DES_ecb_encrypt` present in OpenSSL (or fork).
- `HAVE_GSS_SET_NEG_MECHS`:                 `gss_set_neg_mechs` present in GSS-API library.
- `HAVE_LDAP_INIT_FD`:                      `ldap_init_fd` present in LDAP library.
- `HAVE_LDAP_URL_PARSE`:                    `ldap_url_parse` present in LDAP library.
- `HAVE_MBEDTLS_DES_CRYPT_ECB`:             `mbedtls_des_crypt_ecb` present in mbedTLS <4.
- `HAVE_QUICHE_CONN_SET_QLOG_FD`:           `quiche_conn_set_qlog_fd` present in quiche.
- `HAVE_RUSTLS_SUPPORTED_HPKE`:             `rustls_supported_hpke` present in Rustls
                                            (unused if Rustls is detected via `pkg-config`).
- `HAVE_SSL_SET0_WBIO`:                     `SSL_set0_wbio` present in OpenSSL (or fork).
- `HAVE_SSL_SET1_ECH_CONFIG_LIST`:          `SSL_set1_ech_config_list` present in OpenSSL (or fork).
- `HAVE_SSL_SET_QUIC_TLS_CBS`:              `SSL_set_quic_tls_cbs` in OpenSSL.
- `HAVE_SSL_SET_QUIC_USE_LEGACY_CODEPOINT`: `SSL_set_quic_use_legacy_codepoint` in OpenSSL fork.
- `HAVE_WOLFSSL_BIO_NEW`:                   `wolfSSL_BIO_new` present in wolfSSL.
- `HAVE_WOLFSSL_BIO_SET_SHUTDOWN`:          `wolfSSL_BIO_set_shutdown` present in wolfSSL.
- `HAVE_WOLFSSL_CTX_GENERATEECHCONFIG`:     `wolfSSL_CTX_GenerateEchConfig` present in wolfSSL.
- `HAVE_WOLFSSL_GET_PEER_CERTIFICATE`:      `wolfSSL_get_peer_certificate` present in wolfSSL.
- `HAVE_WOLFSSL_SET_QUIC_USE_LEGACY_CODEPOINT`:
                                            `wolfSSL_set_quic_use_legacy_codepoint` present in wolfSSL.
- `HAVE_WOLFSSL_USEALPN`:                   `wolfSSL_UseALPN` present in wolfSSL.
- `HAVE_WC_DES_ECBENCRYPT`:                 `wc_Des_EcbEncrypt` present in wolfSSL.

For each of the above variables, if the variable is *defined* (either to `ON`
or `OFF`), the symbol detection is skipped. If the variable is *not defined*,
the feature detection is performed.

Note: These variables are internal and subject to change.

## Useful build targets

- `testdeps`:               Build test dependencies (test binaries,
                            test certificates).
                            Test certificates: `build-certs`
                            (clean with `clean-certs`)
- `tests`:                  Run tests (`runtests.pl`). Customize via the `TFLAGS`
                            environment variable, e.g. `TFLAGS=1621`.
                            Other flavors: `test-am`, `test-ci`, `test-event`,
                            `test-full`, `test-nonflaky`, `test-quiet`,
                            `test-torture`
- `tt`:                     Build test binaries (servers, tools).
                            Individual targets: `curlinfo`, `libtests`,
                            `servers`, `tunits`, `units`
- `curl-pytest`:            Run tests (pytest).
                            Other flavor: `curl-test-ci`
- `curl-examples`:          Build examples
                            Individual targets: `curl-example-<name>`,
                            where <name> is the .c filename without extension.
- `curl-examples-build`:    Build examples quickly but without the ability
                            to run them. (for build tests)
- `curl-man`:               Build man pages. (built by default unless disabled)
- `curl`:                   Build curl tool.
- `curl_uninstall`:         Uninstall curl.
- `curl-completion-fish`:   Build shell completions for fish.
                            (built by default if enabled)
- `curl-completion-zsh`:    Build shell completions for zsh.
                            (built by default if enabled)
- `curl-ca-bundle`:         Build the CA bundle via `scripts/mk-ca-bundle.pl`.
- `curl-ca-firefox`:        Build the CA bundle via `scripts/firefox-db2pem.sh`.
- `curl-lint`:              Run lint checks.
- `curl-listcats`:          Generate help category constants for
                            `src/tool_help.h` from documentation.
- `curl-listhelp`:          Generate `src/tool_listhelp.c` from documentation.
- `curl-optiontable`:       Generate `lib/easyoptions.c` from documentation.

# Migrating from Visual Studio IDE Project Files

We recommend using CMake to build curl with MSVC.

The project build files reside in project/Windows/VC\* for VS2010, VS2012 and
VS2013.

These CMake Visual Studio generators require CMake 3.24 or older. You can
download them from <https://cmake.org/files/v3.24/>.

You can also use `-G "NMake Makefiles"`, which is supported by all CMake
versions.

Configuration element             | Equivalent CMake options
:-------------------------------- | :--------------------------------
`VC10`                            | `-G "Visual Studio 10 2010"`
`VC11`                            | `-G "Visual Studio 11 2012"`
`VC12`                            | `-G "Visual Studio 12 2013"`
`x64`                             | `-A x64`
`Win32`                           | `-A Win32`
`DLL`                             | `BUILD_SHARED_LIBS=ON`, `BUILD_STATIC_LIBS=OFF`, (default)
`LIB`                             | `BUILD_SHARED_LIBS=OFF`, `BUILD_STATIC_LIBS=ON`
`Debug`                           | `CMAKE_BUILD_TYPE=Debug` (`-G "NMake Makefiles"` only)
`Release`                         | `CMAKE_BUILD_TYPE=Release` (`-G "NMake Makefiles"` only)
`DLL Windows SSPI`                | `CURL_USE_SCHANNEL=ON` (with SSPI enabled by default)
`DLL OpenSSL`                     | `CURL_USE_OPENSSL=ON`, optional: `OPENSSL_ROOT_DIR`, `OPENSSL_USE_STATIC_LIBS=ON`
`DLL libssh2`                     | `CURL_USE_LIBSSH2=ON`, optional: `LIBSSH2_INCLUDE_DIR`, `LIBSSH2_LIBRARY`
`DLL WinIDN`                      | `USE_WIN32_IDN=ON`

For example these commands:

    > cd projects/Windows
    > ./generate.bat VC12
    > msbuild "-property:Configuration=DLL Debug - DLL Windows SSPI - DLL WinIDN" VC12/curl-all.sln

translate to:

    > cmake . -G "Visual Studio 12 2013" -A x64 -DCURL_USE_SCHANNEL=ON -DUSE_WIN32_IDN=ON -DCURL_USE_LIBPSL=OFF
    > cmake --build . --config Debug --parallel

We do *not* specify `-DCMAKE_BUILD_TYPE=Debug` here as we might do for the
`"NMake Makefiles"` generator because the Visual Studio generators are
[multi-config generators](https://cmake.org/cmake/help/latest/prop_gbl/GENERATOR_IS_MULTI_CONFIG.html)
and therefore ignore the value of `CMAKE_BUILD_TYPE`.
<!--
Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.

SPDX-License-Identifier: curl
-->

# How to install curl and libcurl

## Installing Binary Packages

Lots of people download binary distributions of curl and libcurl. This
document does not describe how to install curl or libcurl using such a binary
package. This document describes how to compile, build and install curl and
libcurl from [source code](https://curl.se/download.html).

## Building from source

You can use autotools or CMake to build curl from source. They work equally
well and have close to feature parity.

autotools' advantages are wide portability and the Unix philosophy, while
CMake typically has faster configuration and build times, and supports MSVC.

Option defaults and dependency detection details may differ.

With both build tools, some features require Perl, and the pytest test suite
requires Python.

You can find live examples for both tools and many build cases in curl's CI
scripts: `.github/workflows/*.yml`, `.circleci/*.yml` and `appveyor.*` (in the
Git repository only). For CMake-specific instructions, see
[INSTALL-CMAKE.md](https://github.com/curl/curl/blob/master/docs/INSTALL-CMAKE.md).

## Building using vcpkg

You can download and install curl and libcurl using
the [vcpkg](https://github.com/Microsoft/vcpkg) dependency manager:

    git clone --depth 1 https://github.com/Microsoft/vcpkg
    cd vcpkg
    ./bootstrap-vcpkg.sh
    ./vcpkg integrate install
    vcpkg install curl[tool]

The curl port in vcpkg is kept up to date by Microsoft team members and
community contributors. If the version is out of date, please [create an issue
or pull request](https://github.com/Microsoft/vcpkg) on the vcpkg repository.

## Building from git

If you get your code off a git repository instead of a release tarball, see
the [GIT-INFO.md](https://github.com/curl/curl/blob/master/GIT-INFO.md) file in
the root directory for specific instructions on how to proceed.

# Unix

A normal Unix installation is made in three or four steps (after you have
unpacked the source archive):

    ./configure --with-openssl [--with-gnutls --with-wolfssl]
    make
    make test (optional)
    make install

(Adjust the configure line accordingly to use the TLS library you want.)

By default curl builds with libpsl (Public Suffix List) support. If libpsl is
not available on your system, install it or disable it with `--without-libpsl`.

You probably need to be root when doing the last command.

Get a full listing of all available configure options by invoking it like:

    ./configure --help

If you want to install curl in a different file hierarchy than `/usr/local`,
specify that when running configure:

    ./configure --prefix=/path/to/curl/tree

If you have write permission in that directory, you can do 'make install'
without being root. An example of this would be to make a local install in
your own home directory:

    ./configure --prefix=$HOME
    make
    make install

The configure script requires you to select a TLS backend explicitly unless
you disable TLS with `--without-ssl`. If you have OpenSSL installed in the
default search path for your compiler/linker, you can run configure like:

    ./configure --with-openssl

If you have OpenSSL installed somewhere else (for example, `/opt/OpenSSL`) and
you have pkg-config installed, set the pkg-config path first, like this:

    env PKG_CONFIG_PATH=/opt/OpenSSL/lib/pkgconfig ./configure --with-openssl

Without pkg-config installed, use this:

    ./configure --with-openssl=/opt/OpenSSL

If you insist on forcing a build without SSL support, you can run configure
like this:

    ./configure --without-ssl

If you have OpenSSL installed, but with the libraries in one place and the
header files somewhere else, you have to set the `LDFLAGS` and `CPPFLAGS`
environment variables prior to running configure. Something like this should
work:

    CPPFLAGS="-I/path/to/ssl/include" LDFLAGS="-L/path/to/ssl/lib" ./configure --with-openssl

If you have shared SSL libs installed in a directory where your runtime
linker does not find them (which usually causes configure failures), you can
provide this option to gcc to set a hard-coded path to the runtime linker:

    LDFLAGS=-Wl,-R/usr/local/ssl/lib ./configure --with-openssl

## Static builds

To force a static library compile, disable the shared library creation by
running configure like:

    ./configure --disable-shared

The configure script is primarily done to work with shared/dynamic third party
dependencies. When linking with shared libraries, the dependency "chain" is
handled automatically by the library loader - on all modern systems.

If you instead link with a static library, you need to provide all the
dependency libraries already at the link command line.

Figuring out all the dependency libraries for a given library is hard, as it
might involve figuring out the dependencies of the dependencies and they vary
between platforms and change between versions.

When using static dependencies, the build scripts mostly assume that you, the
user, provide all the necessary additional dependency libraries as additional
arguments in the build. With configure, by setting `LIBS` or `LDFLAGS` on the
command line.

Building statically is not for the faint of heart.

## Debug

If you are a curl developer and use gcc, you might want to enable curl debug
features (for developing curl) with the `--enable-debug` option.

curl can be built to use a whole range of libraries to provide various useful
services, and configure tries to auto-detect a decent default. If you want to
alter it, you can select how to deal with each individual library.

To debug the build itself, you can set the environment variable
`CURL_TRACE_PKG_CONFIG` to a non-empty value to enable detailed trace
information and verbose errors from `pkg-config` module detection invocations.

## Select TLS backend

These options are provided to select the TLS backend to use.

- AmiSSL: `--with-amissl`
- GnuTLS: `--with-gnutls`.
- mbedTLS: `--with-mbedtls`
- OpenSSL: `--with-openssl` (also for AWS-LC, BoringSSL, LibreSSL, and quictls)
- Rustls: `--with-rustls`
- Schannel: `--with-schannel`
- wolfSSL: `--with-wolfssl`

You can build curl with *multiple* TLS backends at your choice, but some TLS
backends cannot be combined: if you build with an OpenSSL fork (or wolfSSL),
you cannot add another OpenSSL fork (or wolfSSL) because they have
conflicting identical symbol names.

When you build with multiple TLS backends, you can select the active one at
runtime when curl starts up.

### Selecting TLS Trust Anchors Defaults

Verifying a server certificate establishes a chain of trust that needs to
start somewhere. Those "root" certificates make the set of Trust Anchors.

While the build system tries to find good defaults on the platform you
use, you may specify these explicitly. The following options are provided:

- `--with-ca-bundle=FILE`: the file that libcurl loads default root
  certificates from.
- `--with-ca-path=DIRECTORY`: a directory in which root certificates files
  are found.
- `--with-ca-embed=FILE`: a file read *at build time* and added to `libcurl`.
- `--with-ca-fallback`: an OpenSSL specific option for delegating default
  trust anchor selection to what OpenSSL thinks is best, *if* there are
  no other certificates configured by the application.
- `--with-apple-sectrust`: use the system "SecTrust" service on Apple
  operating systems for verification. (Added in 8.17.0)

## MultiSSL and HTTP/3

HTTP/3 needs QUIC and QUIC needs TLS. Building libcurl with HTTP/3 and QUIC
support is not compatible with the MultiSSL feature: they are mutually
exclusive. If you need MultiSSL in your build, you cannot have HTTP/3 support
and vice versa.

libcurl can only use a single TLS library with QUIC and that *same* TLS
library needs to be used for the other TLS using protocols.

## Configure finding libs in wrong directory

When the configure script checks for third-party libraries, it adds those
directories to the `LDFLAGS` variable and then tries linking to see if it
works. When successful, the found directory is kept in the `LDFLAGS` variable
when the script continues to execute and do more tests and possibly check for
more libraries.

This can make subsequent checks for libraries wrongly detect another
installation in a directory that was previously added to `LDFLAGS` by another
library check.

# Windows

Building for Windows Vista/Server 2008 is required as a minimum.

You can build curl with:

- Microsoft Visual Studio 2010 10.0 or greater (`_MSC_VER >= 1600`)
- mingw-w64 3.0 or greater (`__MINGW64_VERSION_MAJOR >= 3`)

## Building Windows DLLs and C runtime (CRT) linkage issues

As a general rule, building a DLL with static CRT linkage is highly
discouraged, and intermixing CRTs in the same app is something to avoid at
any cost.

Reading and comprehending Microsoft Knowledge Base articles KB94248 and
KB140584 is a must for any Windows developer. Especially important is full
understanding if you are not going to follow the advice given above.

- [How To Use the C Runtime](https://learn.microsoft.com/troubleshoot/developer/visualstudio/cpp/libraries/use-c-run-time)
- [Runtime Library Compiler Options](https://learn.microsoft.com/cpp/build/reference/md-mt-ld-use-run-time-library)
- [Potential Errors Passing CRT Objects
  Across DLL Boundaries](https://learn.microsoft.com/cpp/c-runtime-library/potential-errors-passing-crt-objects-across-dll-boundaries)

If your app is misbehaving in some strange way, or it is suffering from memory
corruption, before asking for further help, please try first to rebuild every
single library your app uses as well as your app using the debug
multi-threaded dynamic C runtime.

If you get linkage errors read section 5.7 of the FAQ document.

## Cygwin

Almost identical to the Unix installation. Download the `curl` source code,
then essentially run the configure script in the curl source tree root with
`sh configure`, then run `make`.

To expand on building with Cygwin first ensure it is in your path, and
there are no conflicting tools (*i.e. Chocolatey with sed package*). If so
move Cygwin ahead of any items in your path that would conflict with
Cygwin commands, making sure you have the `sh` executable in `/bin/` or
you see the configure fail toward the end.

Download the setup installer from [Cygwin](https://cygwin.com/) to begin.
Additional Cygwin packages are needed for the install. For more on
installing packages visit
[Cygwin Setup](https://cygwin.com/faq/faq.html#faq.setup.cli).

Either run `setup-x86_64.exe`, then search and select packages individually,
or try:

    setup-x86_64.exe --no-admin -q -I -P binutils,gcc-core,libpsl-devel,libtool,perl,make

Expand the below details to show the list of required packages for a
successful Cygwin install:

<details>
    <summary>Package List</summary>

```
binutils
gcc-core
libpsl-devel
libtool
perl
make
```

</details>

Once all the packages have been installed, begin the process of installing
curl from the source code:

<details>
    <summary>configure_options</summary>

```
--with-gnutls
--with-mbedtls
--with-openssl (also works for OpenSSL forks)
--with-rustls
--with-wolfssl
--without-ssl
```

</details>

1. `sh configure <configure_options>`
2. `make`

> [!Note]
> If an error occurs during the installation, then try:

- Using `cmake` to configure and/or build
- Using `ninja` to build (much faster)
- Reinstalling the required Cygwin packages from the list above without
  passing `-I` to `setup-x86_64`
- Temporarily moving Cygwin to the top of your path
- Installing all of the Cygwin build packages using
  `setup-x86_64 --build-depends curl`

## MS-DOS

You can use either autotools or CMake:

```sh
./configure \
  CC=/path/to/djgpp/bin/i586-pc-msdosdjgpp-gcc \
  AR=/path/to/djgpp/bin/i586-pc-msdosdjgpp-ar \
  RANLIB=/path/to/djgpp/bin/i586-pc-msdosdjgpp-ranlib \
  WATT_ROOT=/path/to/djgpp/net/watt \
  --host=i586-pc-msdosdjgpp \
  --with-openssl=/path/to/djgpp \
  --with-zlib=/path/to/djgpp \
  --without-libpsl \
  --disable-shared
```

```sh
cmake . \
  -DCMAKE_SYSTEM_NAME=DOS \
  -DCMAKE_C_COMPILER_TARGET=i586-pc-msdosdjgpp \
  -DCMAKE_C_COMPILER=/path/to/djgpp/bin/i586-pc-msdosdjgpp-gcc \
  -DWATT_ROOT=/path/to/djgpp/net/watt \
  -DOPENSSL_INCLUDE_DIR=/path/to/djgpp/include \
  -DOPENSSL_SSL_LIBRARY=/path/to/djgpp/lib/libssl.a \
  -DOPENSSL_CRYPTO_LIBRARY=/path/to/djgpp/lib/libcrypto.a \
  -DZLIB_INCLUDE_DIR=/path/to/djgpp/include \
  -DZLIB_LIBRARY=/path/to/djgpp/lib/libz.a \
  -DCURL_USE_LIBPSL=OFF
```

Notes:

- Requires DJGPP 2.04 or greater.

- Compile Watt-32 (and OpenSSL) with the same version of DJGPP. Otherwise
  things go wrong because things like FS-extensions and `errno` values have
  been changed between releases.

## AmigaOS

You can use either autotools or CMake:

```sh
./configure \
  CC=/opt/amiga/bin/m68k-amigaos-gcc \
  AR=/opt/amiga/bin/m68k-amigaos-ar \
  RANLIB=/opt/amiga/bin/m68k-amigaos-ranlib \
  --host=m68k-amigaos \
  --with-amissl \
  CFLAGS='-O0 -msoft-float -mcrt=clib2' \
  CPPFLAGS=-I/path/to/AmiSSL/Developer/include \
  LDFLAGS=-L/path/to/AmiSSL/Developer/lib/AmigaOS3 \
  LIBS='-lnet -lm -latomic' \
  --without-libpsl \
  --disable-shared
```

```sh
cmake . \
  -DAMIGA=1 \
  -DCMAKE_SYSTEM_NAME=Generic \
  -DCMAKE_C_COMPILER_TARGET=m68k-unknown-amigaos \
  -DCMAKE_C_COMPILER=/opt/amiga/bin/m68k-amigaos-gcc \
  -DCMAKE_C_FLAGS='-O0 -msoft-float -mcrt=clib2' \
  -DAMISSL_INCLUDE_DIR=/path/to/AmiSSL/Developer/include \
  -DAMISSL_STUBS_LIBRARY=/path/to/AmiSSL/Developer/lib/AmigaOS3/libamisslstubs.a \
  -DAMISSL_AUTO_LIBRARY=/path/to/AmiSSL/Developer/lib/AmigaOS3/libamisslauto.a \
  -DCURL_USE_LIBPSL=OFF
```

## Disabling Specific Protocols in Windows builds

The configure utility, unfortunately, is not available for the Windows
environment, therefore, you cannot use the various disable-protocol options of
the configure utility on this platform.

You can use specific defines to disable specific protocols and features. See
[CURL-DISABLE](https://github.com/curl/curl/blob/master/docs/CURL-DISABLE.md)
for the full list.

If you want to set any of these defines you have the following options:

- Modify `lib/config-win32.h`
- Modify `lib/curl_setup.h`
- Modify the "Preprocessor Definitions" in the libcurl project

Note: The pre-processor settings can be found using the Visual Studio IDE
under "Project -> Properties -> Configuration Properties -> C/C++ ->
Preprocessor".

## Using BSD-style lwIP instead of Winsock TCP/IP stack in Windows builds

In order to compile libcurl and curl using BSD-style lwIP TCP/IP stack it is
necessary to make the definition of the preprocessor symbol `USE_LWIPSOCK`
visible to libcurl and curl compilation processes. To set this definition you
have the following alternatives:

- Modify `lib/config-win32.h`
- Modify the "Preprocessor Definitions" in the libcurl project

Note: The pre-processor settings can be found using the Visual Studio IDE
under "Project -> Properties -> Configuration Properties -> C/C++ ->
Preprocessor".

Once that libcurl has been built with BSD-style lwIP TCP/IP stack support, in
order to use it with your program it is mandatory that your program includes
lwIP header file `<lwip/opt.h>` (or another lwIP header that includes this)
before including any libcurl header. Your program does not need the
`USE_LWIPSOCK` preprocessor definition which is for libcurl internals only.

Compilation has been verified with lwIP 1.4.0.

This BSD-style lwIP TCP/IP stack support must be considered experimental given
that it has been verified that lwIP 1.4.0 still needs some polish, and libcurl
might yet need some additional adjustment.

## Important static libcurl usage note

When building an application that uses the static libcurl library on Windows,
you must add `-DCURL_STATICLIB` to your `CFLAGS`. Otherwise the linker looks
for dynamic import symbols.

## Legacy Windows and SSL

Schannel (from Windows SSPI), is the native SSL library in Windows. Schannel
in Windows <= XP is unable to connect to servers that no longer support the
legacy handshakes and algorithms used by those versions. If you are using curl
in one of those earlier versions of Windows you should choose another SSL
backend such as OpenSSL.

# Android

When building curl for Android you can either use CMake or `configure`.

Before you can build curl for Android, you need to install the Android NDK
first. This can be done using the SDK Manager that is part of Android Studio.
Once you have installed the Android NDK, you need to figure out where it has
been installed and then set up some environment variables before launching
the build.

Examples to compile for `aarch64` and API level 29:

with CMake, where `ANDROID_NDK_HOME` points into your NDK:

```sh
cmake . \
  -DANDROID_ABI=arm64-v8a \
  -DANDROID_PLATFORM=android-29 \
  -DCMAKE_TOOLCHAIN_FILE="$ANDROID_NDK_HOME/build/cmake/android.toolchain.cmake" \
  -DCURL_ENABLE_SSL=OFF \
  -DCURL_USE_LIBPSL=OFF
```

with `configure`, on macOS:

```sh
export ANDROID_NDK_HOME=~/Library/Android/sdk/ndk/25.1.8937393 # Point into your NDK.
# Same tag for Apple Silicon. Other OS values here:
#   https://developer.android.com/ndk/guides/other_build_systems#overview
export HOST_TAG=darwin-x86_64
export TOOLCHAIN=$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/$HOST_TAG
export AR=$TOOLCHAIN/bin/llvm-ar
export AS=$TOOLCHAIN/bin/llvm-as
export CC=$TOOLCHAIN/bin/aarch64-linux-android29-clang
export CXX=$TOOLCHAIN/bin/aarch64-linux-android29-clang++
export LD=$TOOLCHAIN/bin/ld
export RANLIB=$TOOLCHAIN/bin/llvm-ranlib
export STRIP=$TOOLCHAIN/bin/llvm-strip
```

When building on Linux or targeting other API levels or architectures, you need
to adjust those variables accordingly. After that you can build curl like this:

    ./configure --host aarch64-linux-android --with-pic --disable-shared

Note that this does not give you SSL/TLS support. If you need SSL/TLS, you
have to build curl with an SSL/TLS library, e.g. OpenSSL, because it is
impossible for curl to access Android's native SSL/TLS layer. To build curl
for Android using OpenSSL, follow the OpenSSL build instructions and then
install `libssl.a` and `libcrypto.a` to `$TOOLCHAIN/sysroot/usr/lib` and copy
`include/openssl` to `$TOOLCHAIN/sysroot/usr/include`. Now you can build curl
for Android using OpenSSL like this:

```sh
# For BoringSSL/OpenSSL. In general, you need to the SSL/TLS layer's transitive
# dependencies if you are linking statically.
LIBS='-lssl -lcrypto -lc++'
./configure --host aarch64-linux-android --with-pic --disable-shared --with-openssl="$TOOLCHAIN/sysroot/usr"
```

# IBM i

For IBM i (formerly OS/400), you can use curl in two different ways:

- Natively, running in the **ILE**. The obvious use is being able to call curl
  from ILE C or RPG applications.
- You need to build this from source. See `projects/OS400/README` for the ILE
  specific build instructions.
- In the **PASE** environment, which runs AIX programs. curl is built as it
  would be on AIX.
- IBM provides builds of curl in their Yum repository for PASE software.
- To build from source, follow the Unix instructions.

There are some additional limitations and quirks with curl on this platform;
they affect both environments.

## Multi-threading notes

By default, jobs in IBM i does not start with threading enabled. (Exceptions
include interactive PASE sessions started by `QP2TERM` or SSH.) If you use
curl in an environment without threading when options like asynchronous DNS
were enabled, you get messages like:

```
getaddrinfo() thread failed to start
```

Do not panic. curl and your program are not broken. You can fix this by:

- Set the environment variable `QIBM_MULTI_THREADED` to `Y` before starting
  your program. This can be done at whatever scope you feel is appropriate.
- Alternatively, start the job with the `ALWMLTTHD` parameter set to `*YES`.

# Cross compile

Download and unpack the curl package.

`cd` to the new directory. (e.g. `cd curl-7.12.3`)

Set environment variables to point to the cross-compile toolchain and call
configure with any options you need. Be sure and specify the `--host` and
`--build` parameters at configuration time. The following script is an example
of cross-compiling for the IBM 405GP PowerPC processor using the toolchain on
Linux.

```sh
export PATH=$PATH:/opt/hardhat/devkit/ppc/405/bin
export CPPFLAGS="-I/opt/hardhat/devkit/ppc/405/target/usr/include"
export AR=ppc_405-ar
export AS=ppc_405-as
export LD=ppc_405-ld
export RANLIB=ppc_405-ranlib
export CC=ppc_405-gcc
export NM=ppc_405-nm

./configure \
  --target=powerpc-hardhat-linux \
  --host=powerpc-hardhat-linux \
  --build=i586-pc-linux-gnu \
  --prefix=/opt/hardhat/devkit/ppc/405/target/usr/local \
  --exec-prefix=/usr/local
```

The `--prefix` parameter specifies where curl gets installed. If `configure`
completes successfully, do `make` and `make install` as usual.

In some cases, you may be able to simplify the above commands to as little as:

    ./configure --host=ARCH-OS

# REDUCING SIZE

There are a number of configure options that can be used to reduce the size of
libcurl for embedded applications where binary size is an important factor.
First, be sure to set the `CFLAGS` variable when configuring with any relevant
compiler optimization flags to reduce the size of the binary. For gcc, this
would mean at minimum the `-Os` option, and others like the following that
may be relevant in some environments: `-march=X`, `-mthumb`, `-m32`,
`-mdynamic-no-pic`, `-flto`, `-fdata-sections`, `-ffunction-sections`,
`-fno-unwind-tables`, `-fno-asynchronous-unwind-tables`,
`-fno-record-gcc-switches`, `-fsection-anchors`, `-fno-plt`,
`-Wl,--gc-sections`, `-Wl,-dead_strip` (Apple), `-Wl,-Bsymbolic`, `-Wl,-s`

For example, this is how to combine a few of these options:

    ./configure CC=gcc CFLAGS='-Os -ffunction-sections' LDFLAGS='-Wl,--gc-sections'...

Note that newer compilers often produce smaller code than older versions
due to improved optimization.

Be sure to specify as many `--disable-` and `--without-` flags on the
configure command-line as you can to disable all the libcurl features that you
know your application is not going to need. Besides specifying the
`--disable-PROTOCOL` flags for all the types of URLs your application do not
use, here are some other flags that can reduce the size of the library by
disabling support for some features (run `./configure --help` to see them all):

- `--disable-aws` (cryptographic authentication)
- `--disable-basic-auth` (cryptographic authentication)
- `--disable-bearer-auth` (cryptographic authentication)
- `--disable-digest-auth` (cryptographic authentication)
- `--disable-http-auth` (all HTTP authentication)
- `--disable-kerberos-auth` (cryptographic authentication)
- `--disable-negotiate-auth` (cryptographic authentication)
- `--disable-ntlm` (NTLM authentication)
- `--disable-alt-svc` (HTTP Alt-Svc)
- `--disable-ares` (the C-ARES DNS library)
- `--disable-cookies` (HTTP cookies)
- `--disable-dateparse` (date parsing for time conditionals)
- `--disable-dnsshuffle` (internal server load spreading)
- `--disable-doh` (DNS-over-HTTP)
- `--disable-form-api` (POST form API)
- `--disable-get-easy-options` (lookup easy options at runtime)
- `--disable-headers-api` (API to access headers)
- `--disable-hsts` (HTTP Strict Transport Security)
- `--disable-ipv6` (IPv6)
- `--disable-libcurl-option` (--libcurl C code generation support)
- `--disable-manual` (--manual built-in documentation)
- `--disable-mime` (MIME API)
- `--disable-netrc` (.netrc file)
- `--disable-progress-meter` (graphical progress meter in library)
- `--disable-proxy` (HTTP and SOCKS proxies)
- `--disable-socketpair` (socketpair for asynchronous name resolving)
- `--disable-threaded-resolver` (threaded name resolver)
- `--disable-unix-sockets` (Unix sockets)
- `--disable-verbose` (eliminates debugging strings and error code strings)
- `--disable-versioned-symbols` (versioned symbols)
- `--enable-symbol-hiding` (eliminates unneeded symbols in the shared library)
- `--without-brotli` (Brotli on-the-fly decompression)
- `--without-libpsl` (Public Suffix List in cookies)
- `--without-nghttp2` (HTTP/2 using nghttp2)
- `--without-ngtcp2` (HTTP/2 using ngtcp2)
- `--without-zstd` (Zstd on-the-fly decompression)
- `--without-libidn2` (internationalized domain names)
- `--without-ssl` (SSL/TLS)
- `--without-zlib` (gzip/deflate on-the-fly decompression)

Be sure also to strip debugging symbols from your binaries after compiling
using 'strip' or an option like `-s`. If space is really tight, you may be able
to gain a few bytes by removing some unneeded sections of the shared library
using the -R option to objcopy (e.g. the .comment section).

Using these techniques it is possible to create a basic HTTP-only libcurl
shared library for i386 Linux platforms that is only 137 KiB in size
(as of libcurl version 8.13.0, using gcc 14.2.0).

You may find that statically linking libcurl to your application results in a
lower total size than dynamically linking.

The curl test harness can detect the use of some, but not all, of the
`--disable` statements suggested above. Use of these can cause tests relying
on those features to fail. The test harness can be manually forced to skip the
relevant tests by specifying certain key words on the `runtests.pl` command
line. Following is a list of appropriate key words for those configure options
that are not automatically detected:

- `--disable-cookies`          !cookies
- `--disable-dateparse`        !RETRY-AFTER !`CURLOPT_TIMECONDITION` !`CURLINFO_FILETIME` !`If-Modified-Since` !`curl_getdate` !`-z`
- `--disable-libcurl-option`   !`--libcurl`
- `--disable-verbose`          !verbose\ logs

# Ports

This is a probably incomplete list of known CPU architectures and operating
systems that curl has been compiled for. If you know a system curl compiles
and runs on, that is not listed, please let us know.

## 108 Operating Systems

    AIX, AmigaOS, Android, ArcaOS, Aros, Atari FreeMiNT, Azure Sphere, BeOS,
    Blackberry 10, Blackberry Tablet OS, Cell OS, Cesium, CheriBSD, Chrome OS,
    Cisco IOS, DG/UX, DR DOS, Dragonfly BSD, eCOS, FreeBSD, FreeDOS, FreeRTOS,
    Fuchsia, Garmin OS, Genode, Haiku, HardenedBSD, HP-UX, Hurd, IBM I,
    illumos, Integrity, iOS, ipadOS, IRIX, KasperskyOS, Linux, Lua RTOS,
    Mac OS 9, macOS, Maemo, Mbed, Meego, Micrium, MINIX, Minoca, Moblin,
    MorphOS, MPE/iX, MS-DOS, NCR MP-RAS, NetBSD, Netware, NextStep,
    Nintendo 3DS, Nintendo Switch, NonStop OS, NuttX, OpenBSD, OpenStep,
    Orbis OS, OS/2, OS21, PikeOS, Plan 9, PlayStation Portable, QNX, Qubes OS,
    ReactOS, Redox, RISC OS, ROS, RTEMS, Sailfish OS, SCO Unix, Serenity,
    SINIX-Z, SkyOS, SmartOS, Solaris, Sortix, SunOS, Syllable OS, Symbian,
    Tizen, TPF, Tru64, tvOS, ucLinux, Ultrix, UNICOS, UnixWare, visionOS, VMS,
    vxWorks, watchOS, Wear OS, WebOS, Wii System Software, Wii U, Windows,
    Xbox System, Xenix, z/OS, z/TPF, z/VM, z/VSE, Zephyr

## 28 CPU Architectures

    Alpha, ARC, ARM, AVR32, C-SKY, CompactRISC, Elbrus, ETRAX, HP-PA, Itanium,
    LoongArch, m68k, m88k, MicroBlaze, MIPS, Nios, OpenRISC, POWER, PowerPC,
    RISC-V, s390, SH4, SPARC, Tilera, VAX, x86, Xtensa, z/arch
<!--
Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.

SPDX-License-Identifier: curl
-->

# IPFS

For an overview about IPFS, visit the [IPFS project site](https://ipfs.tech/).

In IPFS there are two protocols. IPFS and IPNS (their workings are explained
in detail [here](https://docs.ipfs.tech/concepts/)). The ideal way to access
data on the IPFS network is through those protocols. For example to access
the Big Buck Bunny video the ideal way to access it is like:
`ipfs://bafybeigagd5nmnn2iys2f3doro7ydrevyr2mzarwidgadawmamiteydbzi`

## IPFS Gateways

IPFS Gateway acts as a bridge between traditional HTTP clients and IPFS.
IPFS Gateway specifications of HTTP semantics can be found
[here](https://specs.ipfs.tech/http-gateways/).

### Deserialized responses

By default, a gateway acts as a bridge between traditional HTTP clients and
IPFS and performs necessary hash verification and deserialization. Through such
gateway, users can download files, directories, and other content-addressed
data stored with IPFS or IPNS as if they were stored in a traditional web
server.

### Verifiable responses

By explicitly requesting
[application/vnd.ipld.raw](https://www.iana.org/assignments/media-types/application/vnd.ipld.raw) or
[application/vnd.ipld.car](https://www.iana.org/assignments/media-types/application/vnd.ipld.car)
responses, by means defined in
[Trustless Gateway Specification](https://specs.ipfs.tech/http-gateways/trustless-gateway/),
the user is able to fetch raw content-addressed data and
[perform hash verification themselves](https://docs.ipfs.tech/reference/http/gateway/#trustless-verifiable-retrieval).

This enables users to use untrusted, public gateways without worrying they
might return invalid/malicious bytes.

## IPFS and IPNS protocol handling

There are various ways to access data from the IPFS network. One such way is
through the concept of public
"[gateways](https://docs.ipfs.tech/concepts/ipfs-gateway/#overview)". The
short version is that entities can offer gateway services. An example here
that is hosted by Protocol Labs (who also makes IPFS) is `dweb.link` and
`ipfs.io`. Both sites expose gateway functionality. Getting a file through
`ipfs.io` looks like this:
`https://ipfs.io/ipfs/bafybeigagd5nmnn2iys2f3doro7ydrevyr2mzarwidgadawmamiteydbzi`

If you were to be [running your own IPFS
node](https://docs.ipfs.tech/how-to/command-line-quick-start/) then you, by
default, also have a [local gateway](https://specs.ipfs.tech/http-gateways/)
running. In its default configuration the earlier example would then also work
in this link:

`http://127.0.0.1:8080/ipfs/bafybeigagd5nmnn2iys2f3doro7ydrevyr2mzarwidgadawmamiteydbzi`

## curl handling of the IPFS protocols

The IPFS integration in curl hides this gateway logic for you. Instead of
providing a full URL to a file on IPFS like this:

```sh
curl http://127.0.0.1:8080/ipfs/bafybeigagd5nmnn2iys2f3doro7ydrevyr2mzarwidgadawmamiteydbzi
```

You can provide it with the IPFS protocol instead:
```sh
curl ipfs://bafybeigagd5nmnn2iys2f3doro7ydrevyr2mzarwidgadawmamiteydbzi
```

With the IPFS protocol way of asking a file, curl still needs to know the
gateway. curl essentially rewrites the IPFS based URL to a gateway URL.

### IPFS_GATEWAY environment variable

If the `IPFS_GATEWAY` environment variable is found, its value is used as
gateway.

### Automatic gateway detection

When you provide no additional details to curl then it:

1. First looks for the `IPFS_GATEWAY` environment variable and use that if it
   is set.
2. Looks for the file: `~/.ipfs/gateway`. If it can find that file then it
   means that you have a local gateway running and that file contains the URL
   to your local gateway.

If curl fails, you are presented with an error message and a link to this page
to the option most applicable to solving the issue.

### `--ipfs-gateway` argument

You can also provide a `--ipfs-gateway` argument to curl. This overrules any
other gateway setting. curl does not fallback to the other options if the
provided gateway did not work.

## Gateway redirects

A gateway could redirect to another place. For example, `dweb.link` redirects
[path based](https://docs.ipfs.tech/how-to/address-ipfs-on-web/#path-gateway)
requests to [subdomain
based](https://docs.ipfs.tech/how-to/address-ipfs-on-web/#subdomain-gateway)
ones. A request using:

    curl ipfs://bafybeigagd5nmnn2iys2f3doro7ydrevyr2mzarwidgadawmamiteydbzi --ipfs-gateway https://dweb.link

Which would be translated to:

    https://dweb.link/ipfs/bafybeigagd5nmnn2iys2f3doro7ydrevyr2mzarwidgadawmamiteydbzi

redirects to:

    https://bafybeigagd5nmnn2iys2f3doro7ydrevyr2mzarwidgadawmamiteydbzi.ipfs.dweb.link

If you trust this behavior from your gateway of choice then passing the `-L`
option follows the redirect.

## Error messages and hints

Depending on the arguments, curl could present the user with an error.

### Gateway file and environment variable

curl tried to look for the file: `~/.ipfs/gateway` but could not find it. It
also tried to look for the `IPFS_GATEWAY` environment variable but could not
find that either. This happens when no extra arguments are passed to curl and
letting it try to figure it out [automatically](#automatic-gateway-detection).

Any IPFS implementation that has gateway support should expose its URL in
`~/.ipfs/gateway`. If you are already running a gateway, make sure it exposes
the file where curl expects to find it.

Alternatively you could set the `IPFS_GATEWAY` environment variable or pass
the `--ipfs-gateway` flag to the curl command.

### Malformed gateway URL

The command executed evaluates in an invalid URL. This could be anywhere in
the URL, but a likely point is a wrong gateway URL.

Inspect the URL set via the `IPFS_GATEWAY` environment variable or passed with
the `--ipfs-gateway` flag. Alternatively opt to go for the
[automatic](#automatic-gateway-detection) gateway detection.
<!--
Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.

SPDX-License-Identifier: curl
-->

# Known bugs intro

These are problems and bugs known to exist at the time of this release. Feel
free to join in and help us correct one or more of these. Also be sure to
check the changelog of the current development status, as one or more of these
problems may have been fixed or changed somewhat since this was written.

# TLS

## IMAPS connection fails with Rustls error

[curl issue 10457](https://github.com/curl/curl/issues/10457)

## Access violation sending client cert with Schannel

When using Schannel to do client certs, curl sets `PKCS12_NO_PERSIST_KEY` to
avoid leaking the private key into the filesystem. Unfortunately that flag
instead seems to trigger a crash.

See [curl issue 17626](https://github.com/curl/curl/issues/17626)

## Client cert (MTLS) issues with Schannel

See [curl issue 3145](https://github.com/curl/curl/issues/3145)

## Schannel TLS 1.2 handshake bug in old Windows versions

In old versions of Windows such as 7 and 8.1 the Schannel TLS 1.2 handshake
implementation likely has a bug that can rarely cause the key exchange to
fail, resulting in error SEC_E_BUFFER_TOO_SMALL or SEC_E_MESSAGE_ALTERED.

[curl issue 5488](https://github.com/curl/curl/issues/5488)

## mbedTLS and CURLE_AGAIN handling

[curl issue 15801](https://github.com/curl/curl/issues/15801)

## Native CA roots incomplete on Windows with OpenSSL (or fork)

Certain Windows installations may be missing CA roots.

[curl issue 20897](https://github.com/curl/curl/issues/20897)
[curl issue 12303](https://github.com/curl/curl/issues/12303)

## ECH not working through Proxy Tunnels

[curl issue 22043](https://github.com/curl/curl/issues/22043)

# Email protocols

## IMAP `SEARCH ALL` truncated response

IMAP `SEARCH ALL` truncates output on large boxes. "A quick search of the code
reveals that `pingpong.c` contains some truncation code, at line 408, when it
deems the server response to be too large truncating it to 40 characters"

https://curl.se/bug/view.cgi?id=1366

## No disconnect command

The disconnect commands (`LOGOUT` and `QUIT`) may not be sent by IMAP, POP3
and SMTP if a failure occurs during the authentication phase of a connection.

## `AUTH PLAIN` for SMTP is not working on all servers

Specifying `--login-options AUTH=PLAIN` on the command line does not seem to
work correctly.

See [curl issue 4080](https://github.com/curl/curl/issues/4080)

## `APOP` authentication fails on POP3

See [curl issue 10073](https://github.com/curl/curl/issues/10073)

## POP3 issue when reading small chunks

    CURL_DBG_SOCK_RMAX=4 ./runtests.pl -v 982

See [curl issue 12063](https://github.com/curl/curl/issues/12063)

# Command line

## `-T /dev/stdin` may upload with an incorrect content length

`-T` stats the path to figure out its size in bytes to use it as
`Content-Length` if it is a regular file.

The problem with that is that on BSD and some other UNIX systems (not Linux),
open(path) may not give you a file descriptor with a 0 offset from the start
of the file.

See [curl issue 12177](https://github.com/curl/curl/issues/12177)

## `-T -` always uploads chunked

When the `<` shell operator is used. curl should realize that stdin is a
regular file in this case, and that it can do a non-chunked upload, like it
would do if you used `-T` file.

See [curl issue 12171](https://github.com/curl/curl/issues/12171)

# Build and portability issues

## OS400 port requires deprecated IBM library

curl for OS400 requires `QADRT` to build, which provides ASCII wrappers for
libc/POSIX functions in the ILE, but IBM no longer supports or even offers
this library to download.

See [curl issue 5176](https://github.com/curl/curl/issues/5176)

## `curl-config --libs` contains private details

`curl-config --libs` include details set in `LDFLAGS` when configure is run
that might be needed only for building libcurl. Further, `curl-config
--cflags` suffers from the same effects with `CFLAGS`/`CPPFLAGS`.

## `LDFLAGS` passed too late making libs linked incorrectly

Compiling latest curl on HP-UX and linking against a custom OpenSSL (which is
on the default loader/linker path), fails because the generated Makefile has
`LDFLAGS` passed on after `LIBS`.

See [curl issue 14893](https://github.com/curl/curl/issues/14893)

## Cygwin: make install installs curl-config.1 twice

[curl issue 8839](https://github.com/curl/curl/issues/8839)

## flaky CI builds

We run many CI builds for each commit and PR on GitHub, and especially a
number of the Windows builds are flaky. This means that we rarely get all CI
builds go green and complete without errors. This is unfortunate as it makes
us sometimes miss actual build problems and it is surprising to newcomers to
the project who (rightfully) do not expect this.

See [curl issue 6972](https://github.com/curl/curl/issues/6972)

## long paths are not fully supported on Windows

curl on Windows cannot access long paths (paths longer than 260 characters).
As a workaround, the Windows path prefix `\\?\` which disables all path
interpretation may work to allow curl to access the path. For example:
`\\?\c:\longpath`.

See [curl issue 8361](https://github.com/curl/curl/issues/8361)

## Unicode on Windows

Passing in a Unicode filename with -o:

[curl issue 11461](https://github.com/curl/curl/issues/11461)

Passing in Unicode character with -d:

[curl issue 12231](https://github.com/curl/curl/issues/12231)

Windows Unicode builds use the home directory in current locale.

The Windows Unicode builds of curl use the current locale, but expect Unicode
UTF-8 encoded paths for internal use such as open, access and stat. The user's
home directory is retrieved via curl_getenv in the current locale and not as
UTF-8 encoded Unicode.

See [curl pull request 7252](https://github.com/curl/curl/pull/7252) and [curl pull request 7281](https://github.com/curl/curl/pull/7281)

Cannot handle Unicode arguments in non-Unicode builds on Windows

If a URL or filename cannot be encoded using the user's current code page then
it can only be encoded properly in the Unicode character set. Windows uses
UTF-16 encoding for Unicode and stores it in wide characters, however curl and
libcurl are not equipped for that at the moment except when built with
_UNICODE and UNICODE defined. Except for Cygwin, Windows cannot use UTF-8 as a
locale.

https://curl.se/bug/?i=345
https://curl.se/bug/?i=731
https://curl.se/bug/?i=3747

NTLM authentication and Unicode

NTLM authentication involving Unicode username or password only works properly
if built with UNICODE defined together with the Schannel backend. The original
problem was mentioned in: https://curl.se/mail/lib-2009-10/0024.html and
https://curl.se/bug/view.cgi?id=896

The Schannel version verified to work as mentioned in
https://curl.se/mail/lib-2012-07/0073.html

# Authentication

## `--aws-sigv4` does not handle multipart/form-data correctly

[curl issue 13351](https://github.com/curl/curl/issues/13351)

## Digest `auth-int` for PUT/POST

We do not support auth-int for Digest using PUT or POST

## Digest does not care for `domain`

libcurl ignores the `domain` directive in Digest authentication challenges
(`WWW-Authenticate:`). RFC 7616 defines it as a quoted, space-separated list
of URIs that define the protection space.

## MIT Kerberos for Windows build

libcurl fails to build with MIT Kerberos for Windows (`KfW`) due to its
library header files exporting symbols/macros that should be kept private to
the library.

## libcurl can fail to try alternatives with `--proxy-any`

When connecting via a proxy using `--proxy-any`, a failure to establish an
authentication causes libcurl to abort trying other options if the failed
method has a higher preference than the alternatives. As an example,
`--proxy-any` against a proxy which advertise Negotiate and NTLM, but which
fails to set up Kerberos authentication does not proceed to try authentication
using NTLM.

[curl issue 876](https://github.com/curl/curl/issues/876)

## Do not clear digest for single realm

[curl issue 3267](https://github.com/curl/curl/issues/3267)

## SHA-256 digest not supported in Windows SSPI builds

Windows builds of curl that have SSPI enabled use the native Windows API calls
to create authentication strings. The call to `InitializeSecurityContext` fails
with `SEC_E_QOP_NOT_SUPPORTED` which causes curl to fail with
`CURLE_AUTH_ERROR`.

Microsoft does not document supported digest algorithms and that `SEC_E` error
code is not a documented error for `InitializeSecurityContext` (digest).

[curl issue 6302](https://github.com/curl/curl/issues/6302)

# FTP

## FTP with ACCT

When doing an operation over FTP that requires the `ACCT` command (but not when
logging in), the operation fails since libcurl does not detect this and thus
fails to issue the correct command: https://curl.se/bug/view.cgi?id=635

## FTPS server compatibility on Windows with Schannel

FTPS is not widely used with the Schannel TLS backend and so there may be more
bugs compared to other TLS backends such as OpenSSL. In the past users have
reported hanging and failed connections. It is likely some changes to curl
since then fixed the issues. None of the reported issues can be reproduced any
longer.

If you encounter an issue connecting to your server via FTPS with the latest
curl and Schannel then please search for open issues or file a new issue.

# SFTP and SCP

## SFTP does not do `CURLOPT_POSTQUOTE` correct

When libcurl sends `CURLOPT_POSTQUOTE` commands when connected to an SFTP
server using the multi interface, the commands are not being sent correctly
and instead the connection is canceled (the operation is considered done)
prematurely. There is a half-baked (busy-looping) patch provided in the bug
report but it cannot be accepted as-is. See
https://curl.se/bug/view.cgi?id=748

## Remote recursive folder creation with SFTP

On this servers, the curl fails to create directories on the remote server
even when the `CURLOPT_FTP_CREATE_MISSING_DIRS` option is set.

See [curl issue 5204](https://github.com/curl/curl/issues/5204)

## libssh blocking and infinite loop problem

In the `SSH_SFTP_INIT` state for libssh, the ssh session working mode is set
to blocking mode. If the network is suddenly disconnected during sftp
transmission, curl is stuck, even if curl is configured with a timeout.

[curl issue 8632](https://github.com/curl/curl/issues/8632)

## Cygwin: "WARNING: UNPROTECTED PRIVATE KEY FILE!"

Running SCP and SFTP tests on Cygwin makes this warning message appear.

[curl issue 11244](https://github.com/curl/curl/issues/11244)

# Connection

## `--interface` with link-scoped IPv6 address

When you give the `--interface` option telling curl to use a specific
interface for its outgoing traffic in combination with an IPv6 address in the
URL that uses a link-local scope, curl might pick the wrong address from the
named interface and the subsequent transfer fails.

Example command line:

    curl --interface eth0 'http://[fe80:928d:xxff:fexx:xxxx]/'

The fact that the given IP address is link-scoped should probably be used as
input to somehow make curl make a better choice for this.

[curl issue 14782](https://github.com/curl/curl/issues/14782)

## Does not acknowledge getaddrinfo sorting policy

Even if a user edits `/etc/gai.conf` to prefer IPv4, curl still prefers and
tries IPv6 addresses first.

[curl issue 16718](https://github.com/curl/curl/issues/16718)

## SOCKS-SSPI discards the security context

After a successful SSPI/GSS-API exchange, the function queries and logs the
authenticated username and reports the supported data-protection level, but
then immediately deletes the negotiated SSPI security context and frees the
credentials before returning. The negotiated context is not stored on the
connection and is therefore never used to protect later SOCKS5 traffic.

## cannot use absolute Unix domain filename for SOCKS on Windows

curl supports using a Unix domain socket path for speaking SOCKS to a proxy,
by providing a filename in the URL used for `-x` (`CURLOPT_PROXY`), but that
path cannot be a proper absolute Windows path with a drive letter etc.

A solution for this probably requires that we add and provide a
`--unix-socket` (`CURLOPT_UNIX_SOCKET_PATH`) option alternative for proxy
communication.

See [curl issue 19825](https://github.com/curl/curl/issues/19825)

# Internals

## GSSAPI library name + version is missing in `curl_version_info()`

The struct needs to be expanded and code added to store this info.

See [curl issue 13492](https://github.com/curl/curl/issues/13492)

## error buffer not set if connection to multiple addresses fails

If you ask libcurl to resolve a hostname like example.com to IPv6 addresses
when you only have IPv4 connectivity. libcurl fails with
`CURLE_COULDNT_CONNECT`, but the error buffer set by `CURLOPT_ERRORBUFFER`
remains empty. Issue: [curl issue 544](https://github.com/curl/curl/issues/544)

## HTTP test server 'connection-monitor' problems

The `connection-monitor` feature of the HTTP test server does not work
properly if some tests are run in unexpected order. Like 1509 and then 1525.

See [curl issue 868](https://github.com/curl/curl/issues/868)

## Connection information when using TCP Fast Open

`CURLINFO_LOCAL_PORT` (and possibly a few other) fails when TCP Fast Open is
enabled.

See [curl issue 1332](https://github.com/curl/curl/issues/1332) and
[curl issue 4296](https://github.com/curl/curl/issues/4296)

## test cases sometimes timeout

Occasionally, one of the tests timeouts. Inexplicably.

See [curl issue 13350](https://github.com/curl/curl/issues/13350)

## `CURLOPT_CONNECT_TO` does not work for HTTPS proxy

It is unclear if the same option should even cover the proxy connection or if
it requires a separate option.

See [curl issue 14481](https://github.com/curl/curl/issues/14481)

## WinIDN test failures

Test 165 disabled when built with WinIDN.

## setting a disabled option should return `CURLE_NOT_BUILT_IN`

When curl has been built with specific features or protocols disabled, setting
such options with `curl_easy_setopt()` should rather return
`CURLE_NOT_BUILT_IN` instead of `CURLE_UNKNOWN_OPTION` to signal the
difference to the application

See [curl issue 15472](https://github.com/curl/curl/issues/15472)

# LDAP

## OpenLDAP hangs after returning results

By configuration defaults, OpenLDAP automatically chase referrals on secondary
socket descriptors. The OpenLDAP backend is asynchronous and thus should
monitor all socket descriptors involved. Currently, these secondary
descriptors are not monitored, causing OpenLDAP library to never receive data
from them.

As a temporary workaround, disable referrals chasing by configuration.

The fix is not easy: proper automatic referrals chasing requires a synchronous
bind callback and monitoring an arbitrary number of socket descriptors for a
single easy handle (currently limited to 5).

Generic LDAP is synchronous: OK.

See [curl issue 622](https://github.com/curl/curl/issues/622) and
https://curl.se/mail/lib-2016-01/0101.html

## LDAP on Windows does authentication wrong?

[curl issue 3116](https://github.com/curl/curl/issues/3116)

## LDAP on Windows does not work

A simple curl command line getting `ldap://ldap.forumsys.com` returns an error
that says `no memory` !

[curl issue 4261](https://github.com/curl/curl/issues/4261)

## LDAPS requests to Active Directory server hang

[curl issue 9580](https://github.com/curl/curl/issues/9580)

# TCP/IP

## telnet code does not handle partial writes properly

It probably does not happen too easily because of how slow and infrequent
sends are normally performed.

## Trying local ports fails on Windows

This makes `--local-port [range]` to not work since curl cannot properly
detect if a port is already in use, so it tries the first port, uses that and
then subsequently fails anyway if that was actually in use.

[curl issue 8112](https://github.com/curl/curl/issues/8112)

# HTTP/2

## HTTP/2 prior knowledge over proxy

[curl issue 12641](https://github.com/curl/curl/issues/12641)

## HTTP/2 frames while in the connection pool kill reuse

If the server sends HTTP/2 frames (like for example an HTTP/2 PING frame) to
curl while the connection is held in curl's connection pool, the socket is
found readable when considered for reuse and that makes curl think it is dead
and then it is closed and a new connection gets created instead.

This is *best* fixed by adding monitoring to connections while they are kept
in the pool so that pings can be responded to appropriately.

## `ENHANCE_YOUR_CALM` causes infinite retries

Infinite retries with 2 parallel requests on one connection receiving `GOAWAY`
with `ENHANCE_YOUR_CALM` error code.

See [curl issue 5119](https://github.com/curl/curl/issues/5119)

## HTTP/2 + TLS spends a lot of time in recv

It has been observed that by making the speed limit less accurate we could
improve this performance. (by reverting
[db5c9f4f9e0779](https://github.com/curl/curl/commit/db5c9f4f9e0779b49624752b135281a0717b277b))
Can we find a golden middle ground?

See https://curl.se/mail/lib-2024-05/0026.html and
[curl issue 13416](https://github.com/curl/curl/issues/13416)

# HTTP/3

## connection migration does not work

[curl issue 7695](https://github.com/curl/curl/issues/7695)

## quiche: QUIC connection is draining

The transfer ends with error "QUIC connection is draining".

[curl issue 12037](https://github.com/curl/curl/issues/12037)

# RTSP

## Some methods do not support response bodies

The RTSP implementation is written to assume that a number of RTSP methods
always get responses without bodies, even though there seems to be no
indication in the RFC that this is always the case.

[curl issue 12414](https://github.com/curl/curl/issues/12414)
<!--
Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.

SPDX-License-Identifier: curl
-->

# Known Risks

This is an incomplete list of known risks when running and using curl and
libcurl.

# Risks

## Insecure transfers

When using curl to perform transfers with protocols that are insecure or the
server identity is unverified, everything that is sent and received can be
intercepted by eavesdroppers and the servers can easily be spoofed by
impostors.

## Untrusted input

You should **never** run curl command lines or use curl config files provided
to you from untrusted sources.

curl can do a lot of things, and you should only ask it do things you want and
deem correct.

Even accepting only the URL part without careful vetting might make curl do
things you do not like. Like accessing internal hosts, like connecting to
rogue servers that redirect to even weirder places, like using ports or
protocols that play tricks on you.

## Command line misuse

The command line tool and its options should be used and be expected to work
as documented. Relying on undocumented functions or side-effects is unreliable
as they may cause problems or get changed behavior between releases.

For several command line options, you can confuse either curl or the involved
server endpoint by using characters or byte sequences for the option that are
not expected. For example, adding line feeds and/or carriage returns to inputs
can produce unexpected, invalid, or insecure results.

## API misuse

Applications using the libcurl API in a way that is not documented to work or
even documented to not work, is unsafe and might cause security problems. We
only guarantee secure and proper functionality when the APIs are used as
documented.

## Local attackers already present

When there is a local attacker present locally, curl cannot prevent such an
adversary to use curl's full potential. Possibly in malicious ways.

## Remote attackers already present

When there is a remote attacker already present in the server, curl cannot
protect its operations against mischief. For example, if an attacker manages
to insert a symlink in your remote upload directory the upload may cause
havoc. Maybe the attacker makes certain responses come back with unexpected
content.

## Debug & Experiments

We encourage users to test curl experiments and use debug code, but only in
controlled environments and setups - never in production.

Using debug builds and experimental curl features in production is a security
risk. Do not do that.

The same applies to scripts and software which are not installed by default
through the make install rule: they are not intended or made for production
use.

## URL inconsistencies

URL parser inconsistencies between browsers and curl are expected and are not
considered security vulnerabilities. The WHATWG URL Specification and RFC
3986+ (the plus meaning that it is an extended version) [are not completely
interoperable](https://github.com/bagder/docs/blob/master/URL-interop.md).

You must never expect two independent URL parsers to treat every URL
identically.

## Visible command line arguments

The curl command blanks the contents of a number of command line arguments to
prevent them from appearing in process listings. It does not blank all
arguments, even though some that are not blanked might contain sensitive data.

- not all systems allow the arguments to be blanked in the first place
- since curl blanks the argument itself they are readable for a short moment
  no matter what
- virtually every argument can contain sensitive data, depending on use
- blanking all arguments would make it impractical for users to differentiate
  curl command lines in process listings

## HTTP headers in redirects

It is powerful to provide a set of custom headers to curl. Beware that when
asking curl to follow HTTP redirects, it also sends those headers to the new
URL which might be a different server. That might do another redirect etc.

curl makes some limited attempts to not leak credentials this way when set
using the standard curl options, but when you pass on custom headers curl
cannot know what headers or details in those headers are sensitive.

## Verbose logs

When asked to provide verbose output and trace logging, curl may output and
show details that are private and sensitive. Like for example raw credentials
or the password weakly disguised using base64 encoding.

## Terminal output and escape sequences

Content that is transferred from a server and gets displayed in a terminal by
curl may contain escape sequences or use other tricks to fool the user. Escape
sequences, moving cursor, changing color etc, is also frequently used for
good. To reduce the risk of getting fooled, save files and browse them after
download using a display method that minimizes risks.

## Legacy dependencies

Every curl build is made to use a range of third party libraries. Each third
party library also needs to be safe and secure for the entire operation to be
risk-free.

Relying on legacy dependencies is a risk.

## Weak algorithms

curl supports several cryptographic algorithms that are considered weak, like
DES and MD5. These algorithms are still in use because some protocols and
transfer options require use of them. For example NTLM or legacy HTTP Digest
authentication.

curl users should consider switching to servers and options that use modern
and secure algorithms.

## Compression bombs

When asking curl or libcurl to automatically decompress data on arrival, there
is a risk that the size of the output from the decompression process ends up
many times larger than the input data size.

Since curl 8.20.0, users can mitigate this risk by setting the max filesize
option that also covers the decompressed size.
<!--
Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.

SPDX-License-Identifier: curl
-->

# Mail etiquette

## About the lists

### Mailing Lists

The mailing lists we have are all listed and described on the [curl
website](https://curl.se/mail/).

Each mailing list is targeted to a specific set of users and subjects, please
use the one or the ones that suit you the most.

Each mailing list has hundreds up to thousands of readers, meaning that each
mail sent is received and read by a large number of people. People from
various cultures, regions, religions and continents.

### Netiquette

Netiquette is a common term for how to behave on the Internet. Of course, in
each particular group and subculture there are differences in what is
acceptable and what is considered good manners.

This document outlines what we in the curl project consider to be good
etiquette, and primarily this focus on how to behave on and how to use our
mailing lists.

### Do Not Mail a Single Individual

Many people send one question to one person. One person gets many mails, and
there is only one person who can give you a reply. The question may be
something that other people would also like to ask. These other people have no
way to read the reply, but to ask the one person the question. The one person
consequently gets overloaded with mail.

If you really want to contact an individual and perhaps pay for his or her
services, by all means go ahead, but if it is another curl question, take it
to a suitable list instead.

### Subscription Required

All curl mailing lists require that you are subscribed to allow a mail to go
through to all the subscribers.

If you post without being subscribed (or from a different mail address than
the one you are subscribed with), your mail is silently discarded. You
have to subscribe first, then post.

The reason for this unfortunate and strict subscription policy is of course to
stop spam from pestering the lists.

### Moderation of new posters

Several of the curl mailing lists automatically make all posts from new
subscribers be moderated. After you have subscribed and sent your first mail
to a list, that mail is not let through to the list until a mailing list
administrator has verified that it is OK and permits it to get posted.

Once a first post has been made that proves the sender is actually talking
about curl-related subjects, the moderation "flag" is switched off and future
posts go through without being moderated.

The reason for this moderation policy is that we do suffer from spammers who
actually subscribe and send spam to our lists.

### Handling trolls and spam

Despite our good intentions and hard work to keep spam off the lists and to
maintain a friendly and positive atmosphere, there are times when spam and or
trolls get through.

Troll - "someone who posts inflammatory, extraneous, or off-topic messages in
an online community"

Spam - "use of electronic messaging systems to send unsolicited bulk messages"

No matter what, we NEVER EVER respond to trolls or spammers on the list. If
you believe the list admin should do something in particular, contact them
off-list. The subject is taken care of as much as possible to prevent repeated
offenses, but responding on the list to such messages never leads to anything
good and only puts the light even more on the offender: which was the entire
purpose of it getting sent to the list in the first place.

Do not feed the trolls.

### How to unsubscribe

You can unsubscribe the same way you subscribed in the first place. You go to
the page for the particular mailing list you are subscribed to and you enter
your email address and password and press the unsubscribe button.

Also, the instructions to unsubscribe are included in the headers of every
mail that is sent out to all curl related mailing lists and there is a footer
in each mail that links to the "admin" page on which you can unsubscribe and
change other options.

You NEVER EVER email the mailing list requesting someone else to take you off
the list.

### I posted, now what?

If you are not subscribed with the same email address that you used to send
the email, your post is silently discarded.

If you posted for the first time to the mailing list, you first need to wait
for an administrator to allow your email to go through (moderated). This
normally happens quickly but in case we are asleep, you may have to wait a few
hours.

Once your email goes through it is sent out to several hundred or even
thousands of recipients. Your email may cover an area that not that many
people know about or are interested in. Or possibly the person who knows about
it is on vacation or under a heavy work load right now. You may have to wait
for a response and you should not expect to get a response at all. Ideally,
you get an answer within a couple of days.

You do yourself and all of us a service when you include as many details as
possible already in your first email. Mention your operating system and
environment. Tell us which curl version you are using and tell us what you
did, what happened and what you expected would happen. Preferably, show us
what you did with details enough to allow others to help point out the problem
or repeat the steps in their locations.

Failing to include details only delays responses and make people respond and
ask for more details and you have to send follow-up emails that include them.

Expect the responses to primarily help YOU debug the issue, or ask YOU
questions that can lead you or others towards a solution or explanation to
whatever you experience.

If you are a repeat offender to the guidelines outlined in this document,
chances are that people ignore you and your chances to get responses in the
future greatly diminish.

### Your emails are public

Your email, its contents and all its headers and the details in those headers
are received by every subscriber of the mailing list that you send your email
to.

Your email as sent to a curl mailing list ends up in mail archives, on the
curl website and elsewhere, for others to see and read. Today and in the
future. In addition to the archives, the mail is sent out to thousands of
individuals. There is no way to undo a sent email.

When sending emails to a curl mailing list, do not include sensitive
information such as usernames and passwords; use fake ones, temporary ones or
remove them completely from the mail. Note that this includes base64 encoded
HTTP Basic auth headers.

This public nature of the curl mailing lists makes automatically inserted mail
footers about mails being "private" or "only meant for the recipient" or
similar even more silly than usual. Because they are absolutely not private
when sent to a public mailing list.

## Sending mail

### Reply or New Mail

Please do not reply to an existing message as a short-cut to post a message to
the lists.

Many mail programs and web archivers use information within mails to keep them
together as "threads", as collections of posts that discuss a certain subject.
If you do not intend to reply on the same or similar subject, do not hit reply
on an existing mail and change the subject, create a new mail.

### Reply to the List

When replying to a message from the list, make sure that you do "group reply"
or "reply to all", and not reply to the author of the single mail you reply
to.

We are actively discouraging replying to the single person by setting the
correct field in outgoing mails back asking for replies to get sent to the
mailing list address, making it harder for people to reply to the author only
by mistake.

### Use a Sensible Subject

Please use a subject of the mail that makes sense and that is related to the
contents of your mail. It makes it a lot easier to find your mail afterwards
and it makes it easier to track mail threads and topics.

### Do Not Top-Post

If you reply to a message, do not use top-posting. Top-posting is when you
write the new text at the top of a mail and you insert the previous quoted
mail conversation below. It forces users to read the mail in a backwards order
to properly understand it.

This is why top posting is so bad (in top posting order):

    A: Because it messes up the order in which people normally read text.
    Q: Why is top-posting such a bad thing?
    A: Top-posting.
    Q: What is the most annoying thing in email?

Apart from the screwed up read order (especially when mixed together in a
thread when someone responds using the mandated bottom-posting style), it also
makes it impossible to quote only parts of the original mail.

When you reply to a mail. You let the mail client insert the previous mail
quoted. Then you put the cursor on the first line of the mail and you move
down through the mail, deleting all parts of the quotes that do not add
context for your comments. When you want to add a comment you do so, inline,
right after the quotes that relate to your comment. Then you continue
downwards again.

When most of the quotes have been removed and you have added your own words,
you are done.

### HTML is not for mails

Please switch off those HTML encoded messages. You can mail all those funny
mails to your friends. We speak plain text mails.

### Quoting

Quote as little as possible. Enough to provide the context you cannot leave
out.

### Digest

We allow subscribers to subscribe to the "digest" version of the mailing
lists. A digest is a collection of mails lumped together in one single mail.

Should you decide to reply to a mail sent out as a digest, there are two
things you MUST consider if you really, really cannot subscribe normally
instead:

Cut off all mails and chatter that is not related to the mail you want to
reply to.

Change the subject name to something sensible and related to the subject,
preferably even the actual subject of the single mail you wanted to reply to

### Please Tell Us How You Solved The Problem

Many people mail questions to the list, people spend some of their time and
make an effort in providing good answers to these questions.

If you are the one who asks, please consider responding once more in case one
of the hints was what solved your problems. The guys who write answers feel
good to know that they provided a good answer and that you fixed the problem.
Far too often, the person who asked the question is never heard from again,
and we never get to know if they are gone because the problem was solved or
perhaps because the problem was unsolvable.

Getting the solution posted also helps other users that experience the same
problem(s). They get to see (possibly in the web archives) that the suggested
fixes actually have helped at least one person.
<!--
Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.

SPDX-License-Identifier: curl
-->

# curl tutorial

## Simple Usage

Get the main page from a web-server:

    curl https://www.example.com/

Get a README file from an FTP server:

    curl ftp://ftp.example.com/README

Get a webpage from a server using port 8000:

    curl http://www.example.com:8000/

Get a directory listing of an FTP site:

    curl ftp://ftp.example.com/

Get all terms matching curl from a dictionary:

    curl dict://dict.example.com/m:curl

Get the definition of curl from a dictionary:

    curl dict://dict.example.com/d:curl

Fetch two documents at once:

    curl ftp://ftp.example.com/ https://www.example.com:8000/

Get a file off an FTPS server:

    curl ftps://files.are.example.com/secrets.txt

or use the more appropriate FTPS way to get the same file:

    curl --ssl-reqd ftp://files.are.example.com/secrets.txt

Get a file from an SSH server using SFTP:

    curl -u username sftp://example.com/etc/issue

Get a file from an SSH server using SCP using a private key (not
password-protected) to authenticate:

    curl -u username: --key ~/.ssh/id_rsa scp://example.com/~/file.txt

Get a file from an SSH server using SCP using a private key
(password-protected) to authenticate:

    curl -u username: --key ~/.ssh/id_rsa --pass private_key_password
      scp://example.com/~/file.txt

Get the main page from an IPv6 web server:

    curl "http://[2001:1890:1112:1::20]/"

Get a file from an SMB server:

    curl -u "domain\username:passwd" smb://server.example.com/share/file.txt

## Download to a File

Get a webpage and store in a local file with a specific name:

    curl -o thatpage.html https://www.example.com/

Get a webpage and store in a local file, make the local file get the name of
the remote document (if no filename part is specified in the URL, this fails):

    curl -O https://www.example.com/index.html

Fetch two files and store them with their remote names:

    curl -O www.haxx.se/index.html -O curl.se/download.html

## Using Passwords

### FTP

To ftp files using name and password, include them in the URL like:

    curl ftp://name:passwd@ftp.server.example:port/full/path/to/file

or specify them with the `-u` flag like

    curl -u name:passwd ftp://ftp.server.example:port/full/path/to/file

### FTPS

It is like FTP, but you may also want to specify and use SSL-specific options
for certificates etc.

Note that using `ftps://` as prefix is the *implicit* way as described in the
standards while the recommended *explicit* way is done by using `ftp://` and
the `--ssl-reqd` option.

### SFTP / SCP

This is similar to FTP, but you can use the `--key` option to specify a
private key to use instead of a password. Note that the private key may itself
be protected by a password that is unrelated to the login password of the
remote system; this password is specified using the `--pass` option.
Typically, curl automatically extracts the public key from the private key
file, but in cases where curl does not have the proper library support, a
matching public key file must be specified using the `--pubkey` option.

### HTTP

curl also supports user and password in HTTP(S) URLs. You can download a file
like:

    curl https://name:passwd@http.server.example/full/path/to/file

or specify user and password separately like in

    curl -u name:passwd https://http.server.example/full/path/to/file

HTTP offers many different methods of authentication and curl supports
several: Basic, Digest, NTLM and Negotiate (SPNEGO). Without telling which
method to use, curl defaults to Basic. You can also ask curl to pick the most
secure ones out of the ones that the server accepts for the given URL, by
using `--anyauth`.

**Note**! According to the URL specification, HTTP URLs can not contain a user
and password, so that style does not work when using curl via a proxy, even
though curl allows it at other times. When using a proxy, you _must_ use the
`-u` style for user and password.

### HTTPS

Probably most commonly used with private certificates, as explained below.

## Proxy

curl supports both HTTP and SOCKS proxy servers, with optional authentication.
It does not have special support for FTP proxy servers since there are no
standards for those, but it can still be made to work with many of them. You
can also use both HTTP and SOCKS proxies to transfer files to and from FTP
servers.

Get an ftp file using an HTTP proxy named my-proxy that uses port 888:

    curl -x my-proxy:888 ftp://ftp.example.com/README

Get a file from an HTTPS server that requires user and password, using the
same proxy as above:

    curl -u user:passwd -x my-proxy:888 https://www.example.com/

Some proxies require special authentication. Specify by using -U as above:

    curl -U user:passwd -x my-proxy:888 https://www.example.com/

A comma-separated list of hosts and domains which do not use the proxy can be
specified as:

    curl --noproxy example.com -x my-proxy:888 https://www.example.com/

If the proxy is specified with `--proxy1.0` instead of `--proxy` or `-x`, then
curl uses HTTP/1.0 instead of HTTP/1.1 for any `CONNECT` attempts.

curl also supports SOCKS4 and SOCKS5 proxies with `--socks4` and `--socks5`.

See also the environment variables curl supports that offer further proxy
control.

Most FTP proxy servers are set up to appear as a normal FTP server from the
client's perspective, with special commands to select the remote FTP server.
curl supports the `-u`, `-Q` and `--ftp-account` options that can be used to
set up transfers through many FTP proxies. For example, a file can be uploaded
to a remote FTP server using a Blue Coat FTP proxy with the options:

    curl -u "username@ftp.server.example Proxy-Username:Remote-Pass"
      --ftp-account Proxy-Password --upload-file local-file
      ftp://my-ftp.proxy.example:21/remote/upload/path/

See the manual for your FTP proxy to determine the form it expects to set up
transfers, and curl's `-v` option to see exactly what curl is sending.

## Piping

Get a key file and install it as a trusted one (when on a system that uses
`apt` for package management):

    curl -L https://apt.example.org/llvm-snapshot.gpg.key | sudo tee
      /etc/apt/trusted.gpg.d/llvm-snapshot.asc >/dev/null

The '|' pipes the output to stdin. `tee` reads from stdin.

## Ranges

HTTP 1.1 introduced byte-ranges. Using this, a client can request to get only
one or more sub-parts of a specified document. curl supports this with the
`-r` flag.

Get the first 100 bytes of a document:

    curl -r 0-99 https://www.example.com/

Get the last 500 bytes of a document:

    curl -r -500 https://www.example.com/

curl also supports simple ranges for FTP files as well. Then you can only
specify start and stop position.

Get the first 100 bytes of a document using FTP:

    curl -r 0-99 ftp://www.example.com/README

## Uploading

### FTP / FTPS / SFTP / SCP

Upload all data on stdin to a specified server:

    curl -T - ftp://ftp.example.com/myfile

Upload data from a specified file, login with user and password:

    curl -T uploadfile -u user:passwd ftp://ftp.example.com/myfile

Upload a local file to the remote site, and use the local filename at the
remote site too:

    curl -T uploadfile -u user:passwd ftp://ftp.example.com/

Upload a local file to get appended to the remote file:

    curl -T localfile -a ftp://ftp.example.com/remotefile

curl also supports ftp upload through a proxy, but only if the proxy is
configured to allow that kind of tunneling. If it does, you can run curl in a
fashion similar to:

    curl --proxytunnel -x proxy:port -T localfile ftp.example.com

### SMB / SMBS

    curl -T file.txt -u "domain\username:passwd"
      smb://server.example.com/share/

### HTTP

Upload all data on stdin to a specified HTTPS site:

    curl -T - https://www.example.com/myfile

Note that the HTTP server must have been configured to accept PUT before this
can be done successfully.

For other ways to do HTTP data upload, see the POST section below.

## Verbose / Debug

If curl fails where it is not supposed to, if the servers do not let you in,
if you cannot understand the responses: use the `-v` flag to get verbose
fetching. curl outputs lots of info and what it sends and receives in order to
let the user see all client-server interaction (but it does not show you the
actual data).

    curl -v ftp://ftp.example.com/

To get even more details and information on what curl does, try using the
`--trace` or `--trace-ascii` options with a given filename to log to, like
this:

    curl --trace my-trace.txt www.haxx.se

## Detailed Information

Different protocols provide different ways of getting detailed information
about specific files/documents. To get curl to show detailed information about
a single file, you should use `-I`/`--head` option. It displays all available
info on a single file for HTTP and FTP. The HTTP information is a lot more
extensive.

For HTTP, you can get the header information (the same as `-I` would show)
shown before the data by using `-i`/`--include`. curl understands the
`-D`/`--dump-header` option when getting files from both FTP and HTTP, and it
then stores the headers in the specified file.

Store the HTTP headers in a separate file (headers.txt in the example):

      curl --dump-header headers.txt curl.se

Note that headers stored in a separate file can be useful at a later time if
you want curl to use cookies sent by the server. More about that in the
cookies section.

## POST (HTTP)

It is easy to post data using curl. This is done using the `-d <data>` option.
The post data must be urlencoded.

Post a simple `name` and `phone` guestbook.

    curl -d "name=Rafael%20Sagula&phone=3320780" https://www.example.com/guest.cgi

Or automatically [URL encode the data](https://everything.curl.dev/http/post/url-encode).

    curl --data-urlencode "name=Rafael Sagula&phone=3320780"
      https://www.example.com/guest.cgi

How to post a form with curl, lesson #1:

Dig out all the `<input>` tags in the form that you want to fill in.

If there is a normal post, you use `-d` to post. `-d` takes a full post
string, which is in the format

    <variable1>=<data1>&<variable2>=<data2>&...

The variable names are the names set with `"name="` in the `<input>` tags, and
the data is the contents you want to fill in for the inputs. The data *must*
be properly URL encoded. That means you replace space with + and that you
replace weird letters with `%XX` where `XX` is the hexadecimal representation
of the letter's ASCII code.

Example:

(say if `https://example.com` had the following html)

```html
<form action="post.cgi" method="post">
  <input name=user size=10>
  <input name=pass type=password size=10>
  <input name=id type=hidden value="blablabla">
  <input name=ding value="submit">
</form>
```

We want to enter user `foobar` with password `12345`.

To post to this, you would enter a curl command line like:

    curl -d "user=foobar&pass=12345&id=blablabla&ding=submit"
      https://example.com/post.cgi

While `-d` uses the application/x-www-form-urlencoded mime-type, generally
understood by CGI's and similar, curl also supports the more capable
multipart/form-data type. This latter type supports things like file upload.

`-F` accepts parameters like `-F "name=contents"`. If you want the contents to
be read from a file, use `@filename` as contents. When specifying a file, you
can also specify the file content type by appending `;type=<mime type>` to the
filename. You can also post the contents of several files in one field.  For
example, the field name `coolfiles` is used to send three files, with
different content types using the following syntax:

    curl -F "coolfiles=@fil1.gif;type=image/gif,fil2.txt,fil3.html"
      https://www.example.com/postit.cgi

If the content-type is not specified, curl tries to guess from the file
extension (it only knows a few), or use the previously specified type (from an
earlier file if several files are specified in a list) or else it uses the
default type `application/octet-stream`.

Emulate a fill-in form with `-F`. Let's say you fill in three fields in a
form. One field is a filename which to post, one field is your name and one
field is a file description. We want to post the file we have written named
`cooltext.txt`. To let curl do the posting of this data instead of your
favorite browser, you have to read the HTML source of the form page and find
the names of the input fields. In our example, the input field names are
`file`, `yourname` and `filedescription`.

    curl -F "file=@cooltext.txt" -F "yourname=Daniel"
      -F "filedescription=Cool text file with cool text inside"
      https://www.example.com/postit.cgi

To send two files in one post you can do it in two ways:

Send multiple files in a single field with a single field name:

    curl -F "pictures=@dog.gif,cat.gif" $URL

Send two fields with two field names

    curl -F "docpicture=@dog.gif" -F "catpicture=@cat.gif" $URL

To send a field value literally without interpreting a leading `@` or `<`, or
an embedded `;type=`, use `--form-string` instead of `-F`. This is recommended
when the value is obtained from a user or some other unpredictable
source. Under these circumstances, using `-F` instead of `--form-string` could
allow a user to trick curl into uploading a file.

## Referrer

An HTTP request has the option to include information about which address
referred it to the actual page. curl allows you to specify the referrer to be
used on the command line. It is especially useful to fool or trick stupid
servers or CGI scripts that rely on that information being available or
contain certain data.

    curl -e www.example.org https://www.example.com/

## User Agent

An HTTP request has the option to include information about the browser that
generated the request. curl allows it to be specified on the command line. It
is especially useful to fool or trick stupid servers or CGI scripts that only
accept certain browsers.

Example:

    curl -A 'Mozilla/3.0 (Win95; I)' https://www.bank.example.com/

Other common strings:

- `Mozilla/3.0 (Win95; I)` - Netscape Version 3 for Windows 95
- `Mozilla/3.04 (Win95; U)` - Netscape Version 3 for Windows 95
- `Mozilla/2.02 (OS/2; U)` - Netscape Version 2 for OS/2
- `Mozilla/4.04 [en] (X11; U; AIX 4.2; Nav)` - Netscape for AIX
- `Mozilla/4.05 [en] (X11; U; Linux 2.0.32 i586)` - Netscape for Linux

Note that Internet Explorer tries hard to be compatible in every way:

- `Mozilla/4.0 (compatible; MSIE 4.01; Windows 95)` - MSIE for W95

Mozilla is not the only possible User-Agent name:

- `Konqueror/1.0` - KDE File Manager desktop client
- `Lynx/2.7.1 libwww-FM/2.14` - Lynx command line browser

## Cookies

Cookies are generally used by web servers to keep state information at the
client's side. The server sets cookies by sending a response line in the
headers that looks like `Set-Cookie: <data>` where the data part then
typically contains a set of `NAME=VALUE` pairs (separated by semicolons `;`
like `NAME1=VALUE1; NAME2=VALUE2;`). The server can also specify for what path
the cookie should be used for (by specifying `path=value`), when the cookie
should expire (`expire=DATE`), for what domain to use it (`domain=NAME`) and
if it should be used on secure connections only (`secure`).

If you have received a page from a server that contains a header like:

```http
Set-Cookie: sessionid=boo123; path="/foo";
```

it means the server wants that first pair passed on when we get anything in a
path beginning with `/foo`.

Example, get a page that wants my name passed in a cookie:

    curl -b "name=Daniel" www.example.com

curl also has the ability to use previously received cookies in following
sessions. If you get cookies from a server and store them in a file in a
manner similar to:

    curl --dump-header headers www.example.com

... you can then in a second connect to that (or another) site, use the
cookies from the `headers.txt` file like:

    curl -b headers.txt www.example.com

While saving headers to a file is a working way to store cookies, it is
however error-prone and not the preferred way to do this. Instead, make curl
save the incoming cookies using the well-known Netscape cookie format like
this:

    curl -c cookies.txt www.example.com

Note that by specifying `-b` you enable the cookie engine and with `-L` you
can make curl follow a `location:` (which often is used in combination with
cookies). If a site sends cookies and a location field, you can use a
non-existing file to trigger the cookie awareness like:

    curl -L -b empty.txt www.example.com

The file to read cookies from must be formatted using plain HTTP headers OR as
Netscape's cookie file. curl determines what kind it is based on the file
contents. In the above command, curl parses the header and store the cookies
received from www.example.com. curl sends the stored cookies which match the
request to the server as it follows the location. The file `empty.txt` may be
a nonexistent file.

To read and write cookies from a Netscape cookie file, you can set both `-b`
and `-c` to use the same file:

    curl -b cookies.txt -c cookies.txt www.example.com

## Progress Meter

The progress meter exists to show a user that something actually is
happening. The different fields in the output have the following meaning:

    % Total    % Received % Xferd  Average Speed          Time             Curr.
                                   Dload  Upload Total    Current  Left    Speed
    0  151M    0 38608    0     0   9406      0  4:41:43  0:00:04  4:41:39  9287

From left-to-right:

- `%`            - percentage completed of the whole transfer
- `Total`        - total size of the whole expected transfer
- `%`            - percentage completed of the download
- `Received`     - currently downloaded amount of bytes
- `%`            - percentage completed of the upload
- `Xferd`        - currently uploaded amount of bytes
- `Average Speed Dload` - the average transfer speed of the download
- `Average Speed Upload` - the average transfer speed of the upload
- `Time Total`   - expected time to complete the operation
- `Time Current` - time passed since the invoke
- `Time Left`    - expected time left to completion
- `Curr.Speed`   - the average transfer speed the last 5 seconds (the first
                   5 seconds of a transfer is based on less time of course.)

The `-#` option displays a totally different progress bar that does not need
much explanation!

## Speed Limit

curl allows the user to set the transfer speed conditions that must be met to
let the transfer keep going. By using the switch `-y` and `-Y` you can make
curl abort transfers if the transfer speed is below the specified lowest limit
for a specified time.

To have curl abort the download if the speed is slower than 3000 bytes per
second for 1 minute, run:

    curl -Y 3000 -y 60 www.far-away.example.com

This can be used in combination with the overall time limit, so that the above
operation must be completed in whole within 30 minutes:

    curl -m 1800 -Y 3000 -y 60 www.far-away.example.com

Forcing curl not to transfer data faster than a given rate is also possible,
which might be useful if you are using a limited bandwidth connection and you
do not want your transfer to use all of it (sometimes referred to as
*bandwidth throttle*).

Make curl transfer data no faster than 10 kilobytes per second:

    curl --limit-rate 10K www.far-away.example.com

or

    curl --limit-rate 10240 www.far-away.example.com

Or prevent curl from uploading data faster than 1 megabyte per second:

    curl -T upload --limit-rate 1M ftp://uploads.example.com

When using the `--limit-rate` option, the transfer rate is regulated on a
per-second basis, which causes the total transfer speed to become lower than
the given number. Sometimes of course substantially lower, if your transfer
stalls during periods.

## Config File

curl automatically tries to read the `.curlrc` file (or `_curlrc` file on
Microsoft Windows systems) from the user's home directory on startup.

The config file could be made up with normal command line switches, but you
can also specify the long options without the dashes to make it more
readable. You can separate the options and the parameter with spaces, or with
`=` or `:`. Comments can be used within the file. If the first letter on a
line is a `#`-symbol the rest of the line is treated as a comment.

If you want the parameter to contain spaces, you must enclose the entire
parameter within double quotes (`"`). Within those quotes, you specify a quote
as `\"`.

NOTE: You must specify options and their arguments on the same line.

Example, set default time out and proxy in a config file:

    # We want a 30 minute timeout:
    -m 1800
    # ... and we use a proxy for all accesses:
    proxy = proxy.our.domain.example.com:8080

Whitespaces ARE significant at the end of lines, but all whitespace leading
up to the first characters of each line are ignored.

Prevent curl from reading the default file by using -q as the first command
line parameter, like:

    curl -q www.example.org

Force curl to get and display a local help page in case it is invoked without
URL by making a config file similar to:

    # default URL to get
    url = "https://help.with.curl.example.com/curlhelp.html"

You can specify another config file to be read by using the `-K`/`--config`
flag. If you set config filename to `-` it reads the config from stdin, which
can be handy if you want to hide options from being visible in process tables
etc:

    echo "user = user:passwd" | curl -K - https://that.secret.example.com

## Extra Headers

When using curl in your own programs, you may end up needing to pass on your
own custom headers when getting a webpage. You can do this by using the `-H`
flag.

Example, send the header `X-you-and-me: yes` to the server when getting a
page:

    curl -H "X-you-and-me: yes" love.example.com

This can also be useful in case you want curl to send a different text in a
header than it normally does. The `-H` header you specify then replaces the
header curl would normally send. If you replace an internal header with an
empty one, you prevent that header from being sent. To prevent the `Host:`
header from being used:

    curl -H "Host:" server.example.com

## FTP and Path Names

Do note that when getting files with a `ftp://` URL, the given path is
relative to the directory you enter. To get the file `README` from your home
directory at your ftp site, do:

    curl ftp://user:passwd@my.example.com/README

If you want the README file from the root directory of that same site, you
need to specify the absolute filename:

    curl ftp://user:passwd@my.example.com//README

(I.e with an extra slash in front of the filename.)

## SFTP and SCP and Path Names

With sftp: and scp: URLs, the path name given is the absolute name on the
server. To access a file relative to the remote user's home directory, prefix
the file with `/~/` , such as:

    curl -u $USER sftp://home.example.com/~/.bashrc

## FTP and Firewalls

The FTP protocol requires one of the involved parties to open a second
connection as soon as data is about to get transferred. There are two ways to
do this.

The default way for curl is to issue the PASV command which causes the server
to open another port and await another connection performed by the
client. This is good if the client is behind a firewall that does not allow
incoming connections.

    curl ftp.example.com

If the server, for example, is behind a firewall that does not allow
connections on ports other than 21 (or if it does not support the `PASV`
command), the other way to do it is to use the `PORT` command and instruct the
server to connect to the client on the given IP number and port (as parameters
to the PORT command).

The `-P` flag to curl supports a few different options. Your machine may have
several IP-addresses and/or network interfaces and curl allows you to select
which of them to use. Default address can also be used:

    curl -P - ftp.example.com

Download with `PORT` but use the IP address of our `le0` interface (this does
not work on Windows):

    curl -P le0 ftp.example.com

Download with `PORT` but use 192.168.0.10 as our IP address to use:

    curl -P 192.168.0.10 ftp.example.com

## Network Interface

Get a webpage from a server using a specified port for the interface:

    curl --interface eth0:1 https://www.example.com/

or

    curl --interface 192.168.1.10 https://www.example.com/

## HTTPS

Secure HTTP requires a TLS library to be installed and used when curl is
built. If that is done, curl is capable of retrieving and posting documents
using the HTTPS protocol.

Example:

    curl https://secure.example.com

curl is also capable of using client certificates to get/post files from sites
that require valid certificates. The only drawback is that the certificate
needs to be in PEM-format. PEM is a standard and open format to store
certificates with, but it is not used by the most commonly used browsers. If
you want curl to use the certificates you use with your favorite browser, you
may need to download/compile a converter that can convert your browser's
formatted certificates to PEM formatted ones.

Example on how to automatically retrieve a document using a certificate with a
personal password:

    curl -E /path/to/cert.pem:password https://secure.example.com/

If you neglect to specify the password on the command line, you are prompted
for the correct password before any data can be received.

Many older HTTPS servers have problems with specific SSL or TLS versions,
which newer versions of OpenSSL etc use, therefore it is sometimes useful to
specify what TLS version curl should use.:

    curl --tlv1.0 https://secure.example.com/

Otherwise, curl attempts to use a sensible TLS default version.

## Resuming File Transfers

To continue a file transfer where it was previously aborted, curl supports
resume on HTTP(S) downloads as well as FTP uploads and downloads.

Continue downloading a document:

    curl -C - -o file ftp://ftp.example.com/path/file

Continue uploading a document:

    curl -C - -T file ftp://ftp.example.com/path/file

Continue downloading a document from a web server

    curl -C - -o file https://www.example.com/

## Time Conditions

HTTP allows a client to specify a time condition for the document it requests.
It is `If-Modified-Since` or `If-Unmodified-Since`. curl allows you to specify
them with the `-z`/`--time-cond` flag.

For example, you can easily make a download that only gets performed if the
remote file is newer than a local copy. It would be made like:

    curl -z local.html https://remote.example.com/remote.html

Or you can download a file only if the local file is newer than the remote
one. Do this by prepending the date string with a `-`, as in:

    curl -z -local.html https://remote.example.com/remote.html

You can specify a plain text date as condition. Tell curl to only download the
file if it was updated since January 12, 2012:

    curl -z "Jan 12 2012" https://remote.example.com/remote.html

curl accepts a wide range of date formats. You always make the date check the
other way around by prepending it with a dash (`-`).

## DICT

For fun try

    curl dict://dict.org/m:curl
    curl dict://dict.org/d:heisenbug:jargon
    curl dict://dict.org/d:daniel:gcide

Aliases for `m` are `match` and `find`, and aliases for `d` are `define` and
`lookup`. For example,

    curl dict://dict.org/find:curl

Commands that break the URL description of the RFC (but not the DICT
protocol) are

    curl dict://dict.org/show:db
    curl dict://dict.org/show:strat

Authentication support is still missing

## LDAP

If you have installed the OpenLDAP library, curl can take advantage of it and
offer `ldap://` support. On Windows, curl uses WinLDAP from Platform SDK by
default.

Default protocol version used by curl is LDAP version 3. Version 2 is used as
a fallback mechanism in case version 3 fails to connect.

LDAP is a complex thing and writing an LDAP query is not an easy
task. Familiarize yourself with the exact syntax description elsewhere. One
such place might be: [RFC 2255, The LDAP URL
Format](https://curl.se/rfc/rfc2255.txt)

To show you an example, this is how to get all people from an LDAP server that
has a certain subdomain in their email address:

    curl -B "ldap://ldap.example.com/o=frontec??sub?mail=*sth.example.com"

You also can use authentication when accessing LDAP catalog:

    curl -u user:passwd "ldap://ldap.example.com/o=frontec??sub?mail=*"
    curl "ldap://user:passwd@ldap.example.com/o=frontec??sub?mail=*"

By default, if user and password are provided, OpenLDAP/WinLDAP uses basic
authentication. On Windows you can control this behavior by providing one of
`--basic`, `--ntlm` or `--digest` option in curl command line

    curl --ntlm "ldap://user:passwd@ldap.example.com/o=frontec??sub?mail=*"

On Windows, if no user/password specified, auto-negotiation mechanism is used
with current logon credentials (SSPI/SPNEGO).

## Environment Variables

curl reads and understands the following proxy related environment variables:

    http_proxy, HTTPS_PROXY, FTP_PROXY

They should be set for protocol-specific proxies. General proxy should be set
with

    ALL_PROXY

A comma-separated list of hostnames that should not go through any proxy is
set in (only an asterisk, `*` matches all hosts)

    NO_PROXY

If the hostname matches one of these strings, or the host is within the domain
of one of these strings, transactions with that node is not done over the
proxy. When a domain is used, it needs to start with a period. A user can
specify that both www.example.com and foo.example.com should not use a proxy
by setting `NO_PROXY` to `.example.com`. By including the full name you can
exclude specific hostnames, so to make `www.example.com` not use a proxy but
still have `foo.example.com` do it, set `NO_PROXY` to `www.example.com`.

The usage of the `-x`/`--proxy` flag overrides the environment variables.

## Netrc

Unix introduced the `.netrc` concept a long time ago. It is a way for a user
to specify name and password for commonly visited FTP sites in a file so that
you do not have to type them in each time you visit those sites. You realize
this is a big security risk if someone else gets hold of your passwords,
therefore most Unix programs do not read this file unless it is only readable
by yourself (curl does not care though).

curl supports `.netrc` files if told to (using the `-n`/`--netrc` and
`--netrc-optional` options). This is not restricted to FTP, so curl can use it
for all protocols where authentication is used.

A simple `.netrc` file could look something like:

    machine curl.se login iamdaniel password mysecret

## Custom Output

To better allow script programmers to get to know about the progress of curl,
the `-w`/`--write-out` option was introduced. Using this, you can specify what
information from the previous transfer you want to extract.

To display the amount of bytes downloaded together with some text and an
ending newline:

    curl -w 'We downloaded %{size_download} bytes\n' www.example.com

## Kerberos FTP Transfer

curl supports kerberos4 and kerberos5/GSSAPI for FTP transfers. You need the
kerberos package installed and used at curl build time for it to be available.

First, get the krb-ticket the normal way, like with the `kinit`/`kauth` tool.
Then use curl in way similar to:

    curl --krb private ftp://krb4site.example.com -u username:fakepwd

There is no use for a password on the `-u` switch, but a blank one makes curl
ask for one and you already entered the real password to `kinit`/`kauth`.

## TELNET

The curl telnet support is basic and easy to use. curl passes all data passed
to it on stdin to the remote server. Connect to a remote telnet server using a
command line similar to:

    curl telnet://remote.example.com

Enter the data to pass to the server on stdin. The result is sent to stdout or
to the file you specify with `-o`.

You might want the `-N`/`--no-buffer` option to switch off the buffered output
for slow connections or similar.

Pass options to the telnet protocol negotiation, by using the `-t` option. To
tell the server we use a vt100 terminal, try something like:

    curl -tTTYPE=vt100 telnet://remote.example.com

Other interesting options for it `-t` include:

- `XDISPLOC=<X display>` Sets the X display location.
- `NEW_ENV=<var,val>` Sets an environment variable.

NOTE: The telnet protocol does not specify any way to login with a specified
user and password so curl cannot do that automatically. To do that, you need to
track when the login prompt is received and send the username and password
accordingly.

## Persistent Connections

Specifying multiple files on a single command line makes curl transfer all of
them, one after the other in the specified order.

libcurl attempts to use persistent connections for the transfers so that the
second transfer to the same host can use the same connection that was already
initiated and was left open in the previous transfer. This greatly decreases
connection time for all but the first transfer and it makes a far better use
of the network.

Note that curl cannot use persistent connections for transfers that are used
in subsequent curl invokes. Try to stuff as many URLs as possible on the same
command line if they are using the same host, as that makes the transfers
faster. If you use an HTTP proxy for file transfers, practically all transfers
are persistent.

## Multiple Transfers With A Single Command Line

As is mentioned above, you can download multiple files with one command line
by adding more URLs. If you want those to get saved to a local file
instead of printed to stdout, you need to add one save option for each URL you
specify. Note that this also goes for the `-O` option (but not
`--remote-name-all`).

For example: get two files and use `-O` for the first and a custom file
name for the second:

    curl -O https://example.com/file.txt ftp://example.com/moo.exe -o moo.jpg

You can also upload multiple files in a similar fashion:

    curl -T local1 ftp://example.com/moo.exe -T local2 ftp://example.com/moo2.txt

## IPv6

curl connects to a server with IPv6 when a host lookup returns an IPv6 address
and fall back to IPv4 if the connection fails. The `--ipv4` and `--ipv6`
options can specify which address to use when both are available. IPv6
addresses can also be specified directly in URLs using the syntax:

    https://[2001:1890:1112:1::20]/overview.html

When this style is used, the `-g` option must be given to stop curl from
interpreting the square brackets as special globbing characters. Link local
and site local addresses including a scope identifier, such as `fe80::1234%1`,
may also be used, but the scope portion must be numeric or match an existing
network interface on Linux and the percent character must be URL escaped. The
previous example in an SFTP URL might look like:

    sftp://[fe80::1234%251]/

IPv6 addresses provided other than in URLs (e.g. to the `--proxy`,
`--interface` or `--ftp-port` options) should not be URL encoded.

## Mailing Lists

For your convenience, we have several open mailing lists to discuss curl, its
development and things relevant to this. Get all info at
https://curl.se/mail/.

Please direct curl questions, feature requests and trouble reports to one of
these mailing lists instead of mailing any individual.

Available lists include:

### `curl-users`

Users of the command line tool. How to use it, what does not work, new
features, related tools, questions, news, installations, compilations,
running, porting etc.

### `curl-library`

Developers using or developing libcurl. Bugs, extensions, improvements.

### `curl-announce`

Low-traffic. Only receives announcements of new public versions. At worst,
that makes something like one or two mails per month, but usually only one
mail every second month.

### `curl-and-php`

Using the curl functions in PHP. Everything curl with a PHP angle. Or PHP with
a curl angle.

### `curl-and-python`

Python hackers using curl with or without the python binding pycurl.
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: mk-ca-bundle
Section: 1
Source: mk-ca-bundle
See-also:
  - curl (1)
Added-in: n/a
---

# NAME

mk-ca-bundle - convert Mozilla's certificate bundle to PEM format

# SYNOPSIS

mk-ca-bundle [options] [output]

# DESCRIPTION

This tool downloads the *certdata.txt* file from Mozilla's source tree over
HTTPS, then parses it and extracts the included certificates into PEM format.
By default, only CA root certificates trusted to issue SSL server
authentication certificates are extracted. These are then processed with the
OpenSSL command line tool to produce the final ca-bundle output file.

The default *output* name is **ca-bundle.crt**. By setting it to '-' (a single
dash) you get the output sent to STDOUT instead of a file.

The PEM format this scripts uses for output makes the result readily available
for use by OpenSSL or GnuTLS powered applications, such as curl and others.

# OPTIONS

The following options are supported:

## -b

backup an existing version of *output*

## -d [name]

specify which Mozilla tree to pull *certdata.txt* from (or a custom URL).
Valid names are: **aurora**, **beta**, **central**, **Mozilla**, **nss**,
**release** (default). They are shortcuts for which source tree to get the
certificate data from.

## -f

force rebuild even if *certdata.txt* is current (Added in version 1.17)

## -i

print version info about used modules

## -k

Allow insecure data transfer. By default (since 1.27) this command fails if
the HTTPS transfer fails. This overrides that decision (and opens for
man-in-the-middle attacks).

## -l

print license info about *certdata.txt*

## -m

(Added in 1.26) Include meta data comments in the output. The meta data is
specific information about each certificate that is stored in the original
file as comments and using this option makes those comments get passed on to
the output file. The meta data is not parsed in any way by mk-ca-bundle.

## -n

Do not download *certdata.txt* - use the existing.

## -p [purposes]:[levels]

list of Mozilla trust purposes and levels for certificates to include in
output. Takes the form of a comma separated list of purposes, a colon, and a
comma separated list of levels. The default is to include all certificates
trusted to issue SSL Server certificates (*SERVER_AUTH:TRUSTED_DELEGATOR*).

Valid purposes are: **ALL**, **DIGITAL_SIGNATURE**, **NON_REPUDIATION**,
**KEY_ENCIPHERMENT**, **DATA_ENCIPHERMENT**, **KEY_AGREEMENT**,
**KEY_CERT_SIGN**, **CRL_SIGN**, **SERVER_AUTH** (default), **CLIENT_AUTH**,
**CODE_SIGNING**, **EMAIL_PROTECTION**, **IPSEC_END_SYSTEM**,
**IPSEC_TUNNEL**, **IPSEC_USER**, **TIME_STAMPING**, **STEP_UP_APPROVED**

Valid trust levels are: **ALL**, **TRUSTED_DELEGATOR** (default), **NOT_TRUSTED**,
**MUST_VERIFY_TRUST**, **TRUSTED**

## -q

be really quiet (no progress output at all)

## -t

include plain text listing of certificates

## -s [algorithms]

A comma separated list of signature algorithms with which to hash/fingerprint
each certificate and output when run in plain text mode.

Valid algorithms are:
ALL, NONE, MD5 (default), SHA1, SHA256, SHA384, SHA512

## -u

unlink (remove) *certdata.txt* after processing

## -v

be verbose and print out processed certificate authorities

# EXIT STATUS

Returns 0 on success. Returns 1 if it fails to download data.

# FILE FORMAT

The file format used by Mozilla for this trust information is [documented
here](https://p11-glue.github.io/p11-glue/doc/storing-trust-policy/storing-trust-existing.html).
<!--
Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.

SPDX-License-Identifier: curl
-->

![curl logo](https://curl.se/logo/curl-logo.svg)

# Documentation

You find a mix of various documentation in this directory and subdirectories,
using several different formats. Some of them are not ideal for reading
directly in your browser.

If you would rather see the rendered version of the documentation, check out the
curl website's [documentation section](https://curl.se/docs/) for
general curl stuff or the [libcurl section](https://curl.se/libcurl/) for
libcurl related documentation.
<!--
Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.

SPDX-License-Identifier: curl
-->

# curl release procedure - how to do a release

## in the source code repo

- edit `RELEASE-NOTES` to be accurate

- update `docs/THANKS`

- update the "past releases" section in `docs/VERSIONS.md`

- make sure all relevant changes are committed on the master branch

- tag the git repo in this style: `git tag -a curl-7_34_0`. -a annotates the
  tag and we use underscores instead of dots in the version number. Make sure
  the tag is GPG signed (using -s).

- run `./scripts/dmaketgz 7.34.0` to build the release tarballs.

- push the git commits and the new tag

- GPG sign the 4 tarballs as `maketgz` suggests

- upload the 8 resulting files to the primary download directory

## in the curl-www repo

- edit `Makefile` (version number and date),

- edit `_changes.html` (insert changes+bugfixes from RELEASE-NOTES)

- commit all local changes

- tag the repo with the same name as used for the source repo.

- make sure all relevant changes are committed and pushed on the master branch

  (the website then updates its contents automatically)

## on GitHub

- edit the newly made release tag so that it is listed as the latest release

## inform

- send an email to curl-users, curl-announce and curl-library. Insert the
  RELEASE-NOTES into the mail.

- if there are any advisories associated with the release, send each markdown
  file to the above lists as well as to `oss-security@lists.openwall.com`
  (unless the problem is unique to the non-open operating systems)

## celebrate

- suitable beverage intake is encouraged for the festivities

# curl release scheduling

## Release Cycle

We normally do releases every 8 weeks on Wednesdays. If important problems
arise, we can insert releases outside the schedule or we can move the release
date.

Each 8 week (56 days) release cycle is divided into three distinct periods:

- During the first 10 calendar days after a release, we are in "cool down". We
  do not merge features but only bug-fixes. If a regression is reported, we
  might do a follow-up patch release.

- During the following 3 weeks (21 days) there is a feature window: we allow
  new features and changes to curl and libcurl. If we accept any such changes,
  we bump the minor number used for the next release.

- During the next 25 days we are in feature freeze. We do not merge any
  features or changes, and we only focus on fixing bugs and polishing things
  to make the pending release a solid one.

If a future release date happens to end up on a "bad date", like in the middle
of common public holidays or when the lead release manager is unavailable, the
release date can be moved forwards or backwards a full week. This is then
advertised well in advance.

# Release Candidates

We ship release candidate tarballs on three occasions in preparation for the
pending release:

- Release candidate one (**rc1**) ships the same Saturday the feature freeze
  starts. Twenty-five days before the release. Tagged like `rc-7_34_0-1`.

- Release candidate two (**rc2**) ships nine days later, sixteen days before
  the release. On a Monday. Tagged like `rc-7_34_0-2`.

- Release candidate three (**rc3**) ships nine days later, seven days before
  the release. On a Wednesday. Tagged like `rc-7_34_0-3`.

Release candidate tarballs are ephemeral and each such tarball is only kept
around for a few weeks. They are provided on their dedicated webpage at:
https://curl.se/rc/

The git tags for release candidates are temporary and remain set only for a
limited period of time.

**Do not use release candidates in production**. They are work in progress.
Use them for testing and verification only. Use actual releases in production.

# Critical problems

We can break the release cycle and do a patch release at any point if a
critical enough problem is reported. There is no exact definition of how to
assess such criticality, but if an issue is highly disturbing or has a
security impact on a large enough share of the user population it might
qualify.

If you think an issue qualifies, bring it to the curl-library mailing list and
push for it.

# Coming dates

Based on the description above, here are some planned future release dates:

- June 24, 2026
- September 2, 2026
- October 28, 2026
- December 23, 2026
- February 17, 2027
- April 14, 2027
# Release tools used for curl 8.22.0

The following tools and their Debian package version numbers were used to
produce this release tarball.

- autoconf: 2.71-3
- automake: 1:1.16.5-1.3
- libtool: 2.4.7-7~deb12u1
- make: 4.3-4.1
- perl: 5.36.0-7+deb12u3
- git: 1:2.39.5-0+deb12u3

# Reproduce the tarball

- Clone the repo and checkout the tag/commit: curl-8_22_0
- Install the same set of tools + versions as listed above

## Do a standard build

- autoreconf -fi
- ./configure [...]
- make

## Generate the tarball with the same timestamp

- export SOURCE_DATE_EPOCH=1788328065
- ./scripts/maketgz [version]

<!--
Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.

SPDX-License-Identifier: curl
-->

# curl the next few years - perhaps

Roadmap of things Daniel Stenberg wants to work on next. It is intended to
serve as a guideline for others for information, feedback and possible
participation.

## WebSocket

Agree that it is a good enough API and remove the EXPERIMENTAL label.

##
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: runtests.pl
Section: 1
Source: runtests
See-also:
  - runtests.pl
Added-in: 7.5
---

# NAME

runtests.pl - run one or more test cases

# SYNOPSIS

**runtests.pl [options] [tests]**

# DESCRIPTION

*runtests.pl* runs one, several or all the existing test cases in curl's
test suite. It is often called from the root Makefile of the curl package with
'make test'.

# TESTS

Specify which test(s) to run by specifying test numbers or keywords.

If no test number or keyword is given, all existing tests that the script can
find are considered for running. You can specify single test cases to run by
specifying test numbers space-separated, like `1 3 5 7 11`, and you can
specify a range of tests like `45 to 67`.

Specify tests to not run with a leading exclamation point, like `!66`, which
runs all available tests except number 66.

Prefix a test number with a tilde (~) to still run it, but ignore the results.

It is also possible to specify tests based on a keyword describing the test(s)
to run, like `FTPS`. The keywords are strings used in the individual tests.

Features are included as keywords with the `feat:` prefix (e.g., `feat:debug`).
Specify a feature to run only tests requiring it, or exclude tests using
`!feat:<feature>`, like `!feat:proxy`, to disable tests which depend on that
feature.

You can also specify keywords with a leading exclamation point and the keyword
or phrase, like "!HTTP NTLM auth" to run all tests **except** those using this
keyword. Remember that the exclamation marks and spaces need to be quoted
somehow when entered at many command shells.

Prefix a keyword with a tilde (~) to still run it, but ignore the results.

# OUTPUT

When running without `-s` (short output), for instance when running
runtests.pl directly rather than via make, each test emits a pair of lines
like this:

    Test 0045...[simple HTTP Location: without protocol in initial URL]
    --pd---e-v- OK (45  out of 1427, remaining: 16:08, took 6.188s, duration: 00:31)

the first line contains the test number and a description. On the second line,
the characters at the beginning are flags indicating which aspects of curl's
behavior were checked by the test:

    s stdout
    r stderr
    p protocol
    d data
    u upload
    P proxy
    o output
    e exit code
    m memory
    v valgrind
    E the test was run event-based

The remainder of the second line contains the test result, current test sequence,
total number of tests to be run and an estimated amount of time to complete the
test run.

# OPTIONS

## `-a`

Continue running the rest of the test cases even if one test fails. By
default, the test script stops as soon as an error is detected.

## `-ac \<curl\>`

Provide a path to a curl binary to talk to APIs (currently only CI test APIs).

## `-am`

Display test results in automake style output (`PASS/FAIL: [number] [name]`).

## `--buildinfo`

Dump `buildinfo.txt`.

## `-c \<curl\>`

Provide a path to a custom curl binary to run the tests with. Default is the
curl executable in the build tree.

## `-d`

Enable protocol debug: have the servers display protocol output. If used in
conjunction with parallel testing, it is difficult to associate the logs with
the specific test being run.

## `-E \<exclude_file\>`

Load the **exclude_file** with additional reasons why certain tests should be
skipped. Useful when testing with external HTTP proxies in which case some of
the tests are not appropriate.

The file contains colon-delimited lines. The first field contains the type of
exclusion, the second field contains a pattern and the final field contains
the reason why matching tests should be skipped. The exclusion types are
*keyword*, *test*, and *tool*.

## `-e` or `--test-event`

Run the test event-based (if possible). This makes runtests invoke curl with
--test-event option. This option only works if both curl and libcurl were
built debug-enabled.

## `-f`

Force the test to run even if mentioned in DISABLED.

## `-g`

Run the given test(s) with gdb. This is best used on a single test case and
curl built --disable-shared. This then fires up gdb with command line set to
run the specified test case. Set a break-point if needed and type 'run' to
start.

## `-gl`

Run the given test(s) with lldb. This is best used on a single test case and
curl built --disable-shared. This then fires up lldb with command line set to
run the specified test case. Set a break-point if needed and type 'run' to
start.

## `-gw`

Run the given test(s) with gdb as a windowed application.

## `-h, --help`

Displays a help text about this program's command line options.

## `-j[num]`

Spawn the given number of processes to run tests in. This defaults to 0 to run
tests serially within a single process. Using a number greater than one allows
multiple tests to run in parallel, speeding up a test run. The optimum number
is dependent on the system and set of tests to run, but 7 times the number of
CPU cores is a good figure to start with, or 1.3 times if Valgrind is in use,
or 5 times for torture tests. Enabling parallel tests is not recommended in
conjunction with the -g option.

## `-L \<file\>`

Load and execute the specified file which should contain perl code. This
option allows one to change *runtests.pl* behavior by overwriting functions
and variables and is useful when testing external proxies using curl's
regression test suite.

## `-l`

Lists all test case names.

## `-m=[seconds]`

Set timeout for curl commands in tests.

## `--min=[count]`

Set the minimum number of tests to run. This overrides the `CURL_TEST_MIN`
environment variable, if any.

## `-n`

Disable the check for and use of valgrind.

## `--no-debuginfod`

Delete the `DEBUGINFOD_URLS` variable if that is defined. Makes valgrind, gdb
etc not able to use this functionality.

## `-o \<variablename=value\>`

Overwrite the specified internal **variable** with **value**. Useful to change
variables that did not get a dedicated flag to change them. Check the source to
see which variables are available.

## `-P \<proxy\>`

Use the specified HTTP proxy when executing tests, even if the tests
themselves do not specify a proxy. This option allows one to test external
proxies using curl's regression test suite.

## `-p`

Prints out all files in the log directory to stdout when a test case fails.
Practical when used in the automated and distributed tests since then the
people checking the failures and the reasons for them might not have physical
access to the machine and logs.

## `-R`

Run the tests in a scrambled, or randomized, order instead of sequentially.

The random seed initially set for this is fixed per month and can be set with
*--seed*.

## `-r`

Display run time statistics. (Requires the `Perl Time::HiRes` module)

## `-rf`

Display full run time statistics. (Requires the `Perl Time::HiRes` module)

## `--repeat=[num]`

This repeats the given set of test numbers this many times. If no test numbers
are given, it repeats ALL tests this many times. It adds the new repeated
sequence at the end of the initially given one.

If **-R** option is also used, the scrambling is done after the repeats have
extended the test sequence.

## `--retry=[num]`

Number of attempts for the whole test run to retry failed tests.

## `-s`

Shorter output. Speaks less than default.

## `--seed=[num]`

When using *--shallow* or *-R* that randomize certain aspects of the behavior,
this option can set the initial seed. If not set, the random seed is set based
on the currently set local year and month and the first line of the "curl -V"
output.

## `--shallow=[num]`

Used together with **-t**. This limits the number of tests to fail in torture
mode to no more than **num** per test case. If this reduces the amount, the
script randomly discards entries to fail until the amount is **num**.

The random seed initially set for this is fixed per month and can be set with
*--seed*.

## `--subset=<section>/<parts>`

Tell runtests to run a subset of the available tests. The test selection is
done first based on existing options. The list of selected tests is then
divided into a number of *parts*. The selected *section* specifier is the
set of tests this invoke runs. Note that both numbers must be provided and
*section* is zero indexed so it must be smaller than *parts*.

Using this option you can for example split up an identical test run into
three separate invokes that combined run all the tests:

     ./runtests.pl --subset=0/3
     ./runtests.pl --subset=1/3
     ./runtests.pl --subset=2/3

This option works fine in combination with `-R` but consider also using
`--seed` for that.

## `-t[num]`

Selects a **torture** test for the given tests. This makes runtests.pl first
run the tests once and count the number of memory allocations made. It then
reruns the test that number of times, each time forcing one of the allocations
to fail until all allocations have been tested. By setting *num* you can force
the allocation with that number to be set to fail at once instead of looping
through everyone, which is handy when debugging and then often in combination
with *-g*.

## `--test-duphandle`

Passes the `--test-duphandle` option to curl when invoked. This command line
option only exists in debug builds and runs curl normally, but duplicates the
easy handle before the transfer and use the duplicate instead of the original
handle. This verifies that the duplicate works exactly as good as the original
handle.

Because of how the curl tool uses a share object to store and keep some data,
not everything is however perfectly copied in the duplicate. In particular
HSTS data is not. A specific test case can be set to avoid using
`--test-duphandle` by disabling it on a per test basis.

## `-u`

Error instead of warning on server unexpectedly alive.

## `-v`

Enable verbose output. Speaks more than by default. If used in conjunction
with parallel testing, it is difficult to associate the logs with the specific
test being run.

## `-vc \<curl\>`

Provide a path to a custom curl binary to run when verifying that the servers
running are indeed our test servers. Default is the curl executable in the
build tree.

# RUNNING TESTS

Many tests have conditions that must be met before the test case can run fine.
They could depend on built-in features in libcurl or features present in the
operating system or even in third-party libraries that curl may or may not
use.

The test script checks most of these by itself to determine when it is safe to
attempt to run each test. Those which cannot be run due to failed requirements
are skipped and listed at the completion of all test cases. In some
unusual configurations, the test script cannot make the correct determination
for all tests. In these cases, the problematic tests can be skipped using the
"!keyword" skip feature documented earlier.

# WRITING TESTS

The simplest way to write test cases is to start with a similar existing test,
save it with a new number and then adjust it to fit. There is an attempt to
document the test case file format in **tests/FILEFORMAT.md**.
<!--
Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.

SPDX-License-Identifier: curl
-->

# Rustls

[Rustls is a TLS backend written in Rust](https://docs.rs/rustls/). curl can
be built to use it as an alternative to OpenSSL or other TLS backends. We use
the [rustls-ffi C bindings](https://github.com/rustls/rustls-ffi). This
version of curl is compatible with `rustls-ffi` v0.15.x.

## Getting rustls-ffi

To build `curl` with `rustls` support you need to have `rustls-ffi` available first.
There are three options for this:

1. Install it from your package manager, if available.
2. Download pre-built binaries.
3. Build it from source.

### Installing rustls-ffi from a package manager

See the [rustls-ffi README] for packaging status. Availability and details for installation
differ between distributions.

Once installed, build `curl` using `--with-rustls`.

    % git clone --depth 1 https://github.com/curl/curl
    % cd curl
    % autoreconf -fi
    % ./configure --with-rustls
    % make

[rustls-ffi README]: https://github.com/rustls/rustls-ffi?tab=readme-ov-file

### Downloading pre-built rustls-ffi binaries

Pre-built binaries are available on the [releases page] on GitHub for releases since 0.15.0.
Download the appropriate archive for your platform and extract it to a directory of your choice
(e.g. `${HOME}/rustls-ffi-built`).

Once downloaded, build `curl` using `--with-rustls` and the path to the extracted binaries.

    % git clone --depth 1 https://github.com/curl/curl
    % cd curl
    % autoreconf -fi
    % ./configure --with-rustls=${HOME}/rustls-ffi-built
    % make

[releases page]: https://github.com/rustls/rustls-ffi/releases

### Building rustls-ffi from source

Building `rustls-ffi` from source requires both a rust compiler, and the [cargo-c] cargo plugin.

To install a Rust compiler, use [rustup] or your package manager to install
the **1.73** or newer toolchain.

To install `cargo-c`, use your [package manager][cargo-c pkg], download
[a pre-built archive][cargo-c prebuilt], or build it from source with `cargo install cargo-c`.

Next, check out, build, and install the appropriate version of `rustls-ffi` using `cargo`:

    % git clone --depth 1 --branch v0.15.3 https://github.com/rustls/rustls-ffi
    % cd rustls-ffi
    % cargo capi install --release --prefix=${HOME}/rustls-ffi-built

Now configure and build `curl` using `--with-rustls`:

    % git clone --depth 1 https://github.com/curl/curl
    % cd curl
    % autoreconf -fi
    % ./configure --with-rustls=${HOME}/rustls-ffi-built
    % make

See the [rustls-ffi README][cryptography provider] for more information on cryptography providers and
their build/platform requirements.

[cargo-c]: https://github.com/lu-zero/cargo-c
[rustup]: https://rustup.rs/
[cargo-c pkg]: https://github.com/lu-zero/cargo-c?tab=readme-ov-file#availability
[cargo-c prebuilt]: https://github.com/lu-zero/cargo-c/releases
[cryptography provider]: https://github.com/cpu/rustls-ffi?tab=readme-ov-file#cryptography-provider
<!--
Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.

SPDX-License-Identifier: curl
-->

# Anatomy of a curl security advisory

As described in the [vulnerability disclosure
policy](https://curl.se/dev/vuln-disclosure.html), when a vulnerability has
been reported to the project and it has been confirmed by the team, we
author an advisory document for the issue.

<p> This advisory document should ideally be written in cooperation with the
reporter to make sure all the angles and details of the problem are gathered
and described correctly and succinctly.

## New document

A security advisory for curl is created in the `docs/` folder in the
[curl-www](https://github.com/curl/curl-www) repository. It should be named
`$CVEID.md` where `$CVEID` is the full CVE Id that has been registered for the
flaw. Like `CVE-2016-0755`. The `.md` extension of course means that the
document is written using markdown.

The standard way to go about this is to first write the `VULNERABILITY`
section for the document, so that there is description of the flaw available,
then paste this description into the CVE Id request.

### `vuln.pm`

The new issue should be entered at the top of the list in the file `vuln.pm`
in the same directory. It holds a large array with all published curl
vulnerabilities. All fields should be filled in accordingly, separated by a
pipe character (`|`).

The fields for every CVE in `vuln.pm` are, in order:

1. HTML page name
2. first vulnerable version
3. last vulnerable version
4. name of the issue
5. CVE Id
6. announce date (`YYYYMMDD`)
7. report to the project date (`YYYYMMDD`)
8. CWE
9. awarded reward amount (USD)
10. area (single word)
11. C-issue (`-` if not a C issue at all, `OVERFLOW` , `OVERREAD`, `DOUBLE_FREE`, `USE_AFTER_FREE`, `NULL_MISTAKE`, `UNINIT`, `BAD_FREE`)
12. affected components: `both`, `lib` or `tool`
13. severity: `low`, `medium`, `high` or `critical`
14. URL to the initial report (often on HackerOne)

### `Makefile`

The new CVE webpage filename needs to be added in the `Makefile`'s `CVELIST`
macro.

When the markdown is in place and the `Makefile` and `vuln.pm` are updated,
all other files and metadata for all curl advisories and versions get
generated automatically using those files.

## Document format

The easy way is to start with a recent previously published advisory and blank
out old texts and save it using a new name. Save the subtitles and general
layout.

Some details and metadata are extracted from this document so it is important
to stick to the existing format.

The first list must be the title of the issue.

### VULNERABILITY

The first subtitle should be `VULNERABILITY`. That should then include a
through and detailed description of the flaw. Including how it can be
triggered and maybe something about what might happen if triggered or
exploited.

### INFO

The next section is `INFO` which adds meta data information about the flaw. It
specifically mentions the official CVE Id for the issue and it must list the
CWE Id, starting on its own line. We write CWE identifiers in advisories with
the full (official) explanation on the right side of a colon. Like this:

`CWE-305: Authentication Bypass by Primary Weakness`

### AFFECTED VERSIONS

The third section first lists what versions that are affected, then adds
clarity by stressing what versions that are *not* affected. A third line adds
information about which specific git commit that introduced the vulnerability.

The `Introduced-in` commit should be a full URL that displays the commit, but
should work as a stand-alone commit hash if everything up to the last slash is
cut out.

An example using the correct syntax:

~~~
- Affected versions: curl 7.16.1 to and including 7.88.1
- Not affected versions: curl < 7.16.1 and curl >= 8.0.0
- Introduced-in: https://github.com/curl/curl/commit/2147284cad
~~~

### THE SOLUTION

This section describes and discusses the fix. The only mandatory information
here is the link to the git commit that fixes the problem.

The `Fixed-in` value should be a full URL that displays the commit, but should
work as a stand-alone commit hash if everything up to the last slash is cut
out.

Example:

`- Fixed-in: https://github.com/curl/curl/commit/af369db4d3833272b8ed`

### RECOMMENDATIONS

This section lists the recommended actions for the users in a top to bottom
priority order and should ideally contain three items but no less than two.

The top two are almost always `upgrade curl to version XXX` and `apply the
patch to your local version`.

### TIMELINE

Detail when this report was received in the project. When package distributors
were notified (via the distros mailing list or similar)

When the advisory and fixed version are released.

### CREDITS

Mention the reporter and patch author at least, then everyone else involved
you think deserves a mention.

If you want to mention more than one name, separate the names with comma
(`,`).

~~~
- Reported-by: Full Name
- Patched-by: Full Name
~~~
<!--
Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.

SPDX-License-Identifier: curl
-->

# curl sponsors

A sponsor is someone who donates money or resources to the curl project for no
specific service in return.

curl accepts donations via [GitHub sponsors](https://github.com/sponsors/curl)
and [Open Collective](https://opencollective.com/curl).

An even better way to contribute to the project might be to pay an engineer or
two to spend work hours on curl related tasks.

We promise to use donated funds for things and activities that we believe are
beneficial for the project and its development. That includes but is not
limited to developer conferences, infrastructure, development, services and
hardware.

Recurring donations above a certain amount of money puts the sponsor at a
named sponsor level: **Silver**, **Gold**, **Platinum** or **Top**.

Sponsors on a named level can provide their logo image and preferred URL and
get recognition on the curl website's [sponsor
page](https://curl.se/sponsors.html), assuming they meet the project's
standards and requirements.

- **Silver Sponsor** at least 100 USD/month
- **Gold Sponsor** at least 500 USD/month
- **Platinum Sponsor** at least 1000 USD/month
- **Top Sponsor** outstanding extra valuable help

## Sponsor requirements

A named level sponsor is entitled a logo and link on the curl website assuming
the company, brand and link are not deemed unsuitable. The curl team reserves
the right to make that decision at its own discretion.

Sponsors may be denied a website presence for example if involved with drugs,
gambling, pornography, social media manipulation etc.

## Past Sponsors

Sponsors that stop paying are considered *Past Sponsors* and are not displayed
on the sponsor page anymore. We thank you for your contributions.

## Donations

Please note that sponsorship and donations are exactly that: donations to the
curl project. They are used to help and further the project as the project
leadership deems best. No goods or services are expected or promised in
return. Requests for refunds for such purposes are rejected.
<!--
Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.

SPDX-License-Identifier: curl
-->

# TLS Certificate Verification

## Native vs file based

If curl was built with Schannel support, then curl uses the Windows native CA
store for verification. On Apple operating systems, it is possible to use Apple's
"SecTrust" services for certain TLS backends, details below.
All other TLS libraries use a file based CA store by
default.

## Verification

Every trusted server certificate is digitally signed by a Certificate
Authority, a CA.

In your local CA store you have a collection of certificates from *trusted*
certificate authorities that TLS clients like curl use to verify servers.

curl does certificate verification by default. This is done by verifying the
signature and making sure the certificate was crafted for the server name
provided in the URL.

If you communicate with HTTPS, FTPS or other TLS-using servers using
certificates signed by a CA whose certificate is present in the store, you can
be sure that the remote server really is the one it claims to be.

If the remote server uses a self-signed certificate, if you do not install a
CA cert store, if the server uses a certificate signed by a CA that is not
included in the store you use or if the remote host is an impostor
impersonating your favorite site, the certificate check fails and reports an
error.

If you think it wrongly failed the verification, consider one of the following
sections.

### Skip verification

Tell curl to *not* verify the peer with `-k`/`--insecure`.

We **strongly** recommend this is avoided and that even if you end up doing
this for experimentation or development, **never** skip verification in
production.

### Use a custom CA store

Get a CA certificate that can verify the remote server and use the proper
option to point out this CA cert for verification when connecting - for this
specific transfer only.

With the curl command line tool: `--cacert [file]`

If you use the curl command line tool without a native CA store, then you can
specify your own CA cert file by setting the environment variable
`CURL_CA_BUNDLE` to the path of your choice. `SSL_CERT_FILE` and `SSL_CERT_DIR`
are also supported.

If you are using the curl command line tool on Windows, curl searches for a CA
cert file named `curl-ca-bundle.crt` in these directories and in this order:
  1. application's directory
  2. current working directory
  3. Windows System directory (e.g. C:\Windows\System32)
  4. Windows Directory (e.g. C:\Windows)
  5. all directories along %PATH%

curl 8.11.0 added a build-time option to disable this search behavior, and
another option to restrict search to the application's directory.

curl 8.19.0 added a build-time option to enable Native CA by default on
Windows. This build-time option by default also disables searching for
a `curl-ca-bundle.crt` on disk.

### Use the native store

In several environments, in particular on Microsoft and Apple operating
systems, you can ask curl to use the system's native CA store when verifying
the certificate. Depending on how curl was built, this may already be the
default.

With the curl command line tool: `--ca-native`.

### Modify the CA store

Add the CA cert for your server to the existing default CA certificate store.

Usually you can figure out the path to the local CA store by looking at the
verbose output that `curl -v` shows when you connect to an HTTPS site.

### Change curl's default CA store

The default CA certificate store curl uses is set at build time. When you
build curl you can point out your preferred path.

### Extract CA cert from a server

    curl -w %{certs} https://example.com > cacert.pem

The certificate has `BEGIN CERTIFICATE` and `END CERTIFICATE` markers.

### Get the Mozilla CA store

Download a version of the Firefox CA store converted to PEM format on the [CA
Extract](https://curl.se/docs/caextract.html) page. It always features the
latest Firefox bundle.

## Native CA store

### Windows + Schannel

If curl was built with Schannel, then curl uses the certificates that are
built into the OS. These are the same certificates that appear in the
Internet Options control panel (under Windows).
Any custom security rules for certificates are honored.

Schannel runs CRL checks on certificates unless peer verification is disabled.

### Apple + OpenSSL/GnuTLS

When curl is built with Apple SecTrust enabled and uses an OpenSSL compatible
TLS backend or GnuTLS, the default verification is handled by that Apple
service. As in:

    curl https://example.com

You may still provide your own certificates on the command line, such as:

    curl --cacert mycerts.pem https://example.com

In this situation, Apple SecTrust is **not** used and verification is done
**only** with the trust anchors found in `mycerts.pem`. If you want **both**
Apple SecTrust and your own file to be considered, use:

    curl --ca-native --cacert mycerts.pem https://example.com

#### Other Combinations

How well the use of native CA stores work in all other combinations depends
on the TLS backend and the OS. Many TLS backends offer functionality to access
the native CA on a range of operating systems. Some provide this only on specific
configurations.

Specific support in curl exists for Windows and OpenSSL compatible TLS backends.
It tries to load the certificates from the Windows "CA" and "ROOT" stores for
transfers requesting the native CA. Due to Window's delayed population of those
stores, this might not always find all certificates.

## HTTPS proxy

curl can do HTTPS to the proxy separately from the connection to the server.
This TLS connection is handled and verified separately from the server
connection so instead of `--insecure` and `--cacert` to control the
certificate verification, you use `--proxy-insecure` and `--proxy-cacert`.
With these options, you make sure that the TLS connection and the trust of the
proxy can be kept totally separate from the TLS connection to the server.
<!--
Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.

SPDX-License-Identifier: curl
-->

# SSL problems

First, let's establish that we often refer to TLS and SSL interchangeably as
SSL here. The current protocol is called TLS, it was called SSL a long time
ago.

There are several known reasons why a connection that involves SSL might
fail. This is a document that attempts to detail the most common ones and
how to mitigate them.

## CA certs

CA certs are used to digitally verify the server's certificate. You need a
"ca bundle" for this. See lots of more details on this in the `SSLCERTS`
document.

## CA bundle missing intermediate certificates

When using said CA bundle to verify a server cert, you may experience
problems if your CA store does not contain the certificates for the
intermediates if the server does not provide them.

The TLS protocol mandates that the intermediate certificates are sent in the
handshake, but as browsers have ways to survive or work around such
omissions, missing intermediates in TLS handshakes still happen that browser
users do not notice.

Browsers work around this problem in two ways: they cache intermediate
certificates from previous transfers and some implement the TLS "AIA"
extension that lets the client explicitly download such certificates on
demand.

## Protocol version

Some broken servers fail to support the protocol negotiation properly that
SSL servers are supposed to handle. This may cause the connection to fail
completely. Sometimes you may need to explicitly select an SSL version to
use when connecting to make the connection succeed.

An additional complication can be that modern SSL libraries sometimes are
built with support for older SSL and TLS versions disabled.

All versions of SSL and the TLS versions before 1.2 are considered insecure
and should be avoided. Use TLS 1.2 or later.

## Ciphers

Clients give servers a list of ciphers to select from. If the list does not
include any ciphers the server wants/can use, the connection handshake
fails.

curl has recently disabled the user of a whole bunch of seriously insecure
ciphers from its default set (slightly depending on SSL backend in use).

You may have to explicitly provide an alternative list of ciphers for curl
to use to allow the server to use a weak cipher for you.

Note that these weak ciphers are identified as flawed. For example, this
includes symmetric ciphers with less than 128-bit keys and RC4.

Schannel in Windows XP is not able to connect to servers that no longer
support the legacy handshakes and algorithms used by those versions, so we
advise against building curl to use Schannel on really old Windows versions.

Reference: [Prohibiting RC4 Cipher
Suites](https://datatracker.ietf.org/doc/html/draft-popov-tls-prohibiting-rc4-01)

## Allow BEAST

BEAST is the name of a TLS 1.0 attack that surfaced 2011. When adding means
to mitigate this attack, it turned out that some broken servers out there in
the wild did not work properly with the BEAST mitigation in place.

To make such broken servers work, the --ssl-allow-beast option was
introduced. Exactly as it sounds, it re-introduces the BEAST vulnerability
but on the other hand it allows curl to connect to that kind of strange
servers.

## Disabling certificate revocation checks

Some SSL backends may do certificate revocation checks (CRL, OCSP, etc)
depending on the OS or build configuration. The --ssl-no-revoke option was
introduced in 7.44.0 to disable revocation checking but currently is only
supported for Schannel (the native Windows SSL library), with an exception
in the case of Windows' Untrusted Publishers block list which it seems cannot
be bypassed. This option may have broader support to accommodate other SSL
backends in the future.

References:

https://curl.se/docs/ssl-compared.html
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: testcurl.pl
Section: 1
Source: testcurl
See-also:
  - runtests.pl
Added-in: 7.11.2
---

# NAME

testcurl.pl - (automatically) test curl

# SYNOPSIS

**testcurl.pl [options] [dir] \> output**

# DESCRIPTION

*testcurl* is the master script to use for automatic distributed testing of
curl from git or daily snapshots. It is written for the purpose of being run
from a crontab job or similar at a regular interval. The output is suitable to
be mailed to **curl-autocompile@haxx.se** to be dealt with automatically (make
sure the subject includes the word "autobuild" as the mail gets silently
discarded otherwise). The most current build status (with a reasonable
backlog) is published on the curl site, at https://curl.se/dev/builds.html

*options* may be omitted. See *--setup* for what happens then.

*dir* is a curl source directory, possibly a daily snapshot one. Using this
makes *testcurl* skip the *autoreconf* stage and thus it removes the
dependency on automake, autoconf, libtool, GNU m4 and possibly a few other
things.

*testcurl* runs `autoreconf` (or similar), configure, builds curl and libcurl
in a separate build directory and then runs `make test` to test the fresh
build.

# OPTIONS

## `--configure=[options]`

Configure options passed to configure.

## `--crosscompile`

This is a cross-compile. Makes *testcurl* skip a few things.

## `--desc=[desc]`

Description of your test system. Displayed on the build summary page on the
website.

## `--email=[email]`

Set email address to report as. Displayed in the build logs on the site.

## `--mktarball=[command]`

Generic command to run after completed test.

## `--name=[name]`

Set name to report as. Displayed in the build summary on the site.

## `--nobuildconf`

Do not run autoreconf. Useful when many builds use the same source tree, as
then only one need to do this. Also, if multiple processes run tests
simultaneously on the same source tree (like several hosts on a NFS mounted
directory), simultaneous autoreconf invokes may cause problems. (Added in
7.14.1)

## `--nogitpull`

Do not update from git even though it is a git tree. Useful to still be able
to test even though your network is down, or similar.

## `--runtestopts=[options]`

Options that is passed to the runtests script. Useful for disabling valgrind
by force, and similar.

## `--setup=[filename]`

filename to read setup from (deprecated). The old style of providing info. If
info is missing when *testcurl* is started, it prompts you and then stores the
info in a 'setup' file, which it looks for on each invoke. Use *--name*,
*--email*, *--configure* and *--desc* instead.

## `--target=[your os]`

Specify your target environment. Recognized strings include `vc`, `mingw32`,
and `borland`.

# INITIAL SETUP

First, make a checkout from git (or you write a script that downloads daily
snapshots automatically):

    $ mkdir curl-testing
    $ cd curl-testing
    $ git clone https://github.com/curl/curl

With the curl sources checked out, or downloaded, you can start testing right
away. If you want to use *testcurl* without command line arguments and to have
it store and remember the config in its 'setup' file, then start it manually
now and fill in the answers to the questions it prompts you for:

    $ ./curl/tests/testcurl

Now you are ready to go. If you let the script run, it performs a full cycle
and spit out lots of output. Mail us that output as described above.

# CRONTAB EXAMPLE

The crontab could include something like this:

    # autobuild curl:
    0 4 * * * cd curl-testing && ./testit.sh

Where `testit.sh` is a shell script that could look similar to this:

    mail="mail -s autobuild curl-autocompile@haxx.se"
    name="--name=whoami"
    email="--email=iamme@nowhere"
    desc='"--desc=supermachine Turbo 2000"'
    testprog="perl ./curl/tests/testcurl.pl $name $email $desc"
    opts1="--configure=--enable-debug"
    opts2="--configure=--enable-ipv6"

    # run first test
    $testprog $opts1 | $mail

    # run second test
    $testprog $opts2 | $mail
<!--
Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.

SPDX-License-Identifier: curl
-->

# The Art Of Scripting HTTP Requests Using curl

## Background

This document assumes that you are familiar with HTML and general networking.

The increasing amount of applications moving to the web has made "HTTP
Scripting" more frequently requested and wanted. To be able to automatically
extract information from the web, to fake users, to post or upload data to
web servers are all important tasks today.

curl is a command line tool for doing all sorts of URL manipulations and
transfers, but this particular document focuses on how to use it when doing
HTTP requests for fun and profit. This documents assumes that you know how to
invoke `curl --help` or `curl --manual` to get basic information about it.

curl is not written to do everything for you. It makes the requests, it gets
the data, it sends data and it retrieves the information. You probably need
to glue everything together using some kind of script language or repeated
manual invokes.

## The HTTP Protocol

HTTP is the protocol used to fetch data from web servers. It is a simple
protocol that is built upon TCP/IP. The protocol also allows information to
get sent to the server from the client using a few different methods, as is
shown here.

HTTP is plain ASCII text lines being sent by the client to a server to
request a particular action, and then the server replies a few text lines
before the actual requested content is sent to the client.

The client, curl, sends an HTTP request. The request contains a method (like
GET, POST, HEAD etc), a number of request headers and sometimes a request
body. The HTTP server responds with a status line (indicating if things went
well), response headers and most often also a response body. The "body" part
is the plain data you requested, like the actual HTML or the image etc.

## See the Protocol

Using curl's option [`--verbose`](https://curl.se/docs/manpage.html#-v) (`-v`
as a short option) displays what kind of commands curl sends to the server,
as well as a few other informational texts.

`--verbose` is the single most useful option when it comes to debug or even
understand the curl<->server interaction.

Sometimes even `--verbose` is not enough. Then
[`--trace`](https://curl.se/docs/manpage.html#-trace) and
[`--trace-ascii`](https://curl.se/docs/manpage.html#--trace-ascii)
offer even more details as they show **everything** curl sends and
receives. Use it like this:

    curl --trace-ascii debugdump.txt https://www.example.com/

## See the Timing

Many times you may wonder what exactly is taking all the time, or you want to
know the amount of milliseconds between two points in a transfer. For those,
and other similar situations, the
[`--trace-time`](https://curl.se/docs/manpage.html#--trace-time) option is
what you need. It prepends the time to each trace output line:

    curl --trace-ascii d.txt --trace-time https://example.com/

## See which Transfer

When doing parallel transfers, it is relevant to see which transfer is doing
what. When response headers are received (and logged) you need to know which
transfer these are for.
[`--trace-ids`](https://curl.se/docs/manpage.html#--trace-ids) option is what
you need. It prepends the transfer and connection identifier to each trace
output line:

    curl --trace-ascii d.txt --trace-ids https://example.com/

## See the Response

By default curl sends the response to stdout. You need to redirect it
somewhere to avoid that, most often that is done with `-o` or `-O`.

# URL

## Spec

The Uniform Resource Locator format is how you specify the address of a
particular resource on the Internet. You know these, you have seen URLs like
https://curl.se/ or https://example.com/ a million times. RFC 3986 is the
canonical spec. The formal name is not URL, it is **URI**.

## Host

The hostname is usually resolved using DNS or your /etc/hosts file to an IP
address and that is what curl communicates with. Alternatively you specify
the IP address directly in the URL instead of a name.

For development and other trying out situations, you can point to a different
IP address for a hostname than what would otherwise be used, by using curl's
[`--resolve`](https://curl.se/docs/manpage.html#--resolve) option:

    curl --resolve www.example.org:80:127.0.0.1 https://www.example.org/

## Port number

Each protocol curl supports operates on a default port number, be it over TCP
or in some cases UDP. Normally you do not have to take that into
consideration, but at times you run test servers on other ports or
similar. Then you can specify the port number in the URL with a colon and a
number immediately following the hostname. Like when doing HTTP to port
1234:

    curl https://www.example.org:1234/

The port number you specify in the URL is the number that the server uses to
offer its services. Sometimes you may use a proxy, and then you may
need to specify that proxy's port number separately from what curl needs to
connect to the server. Like when using an HTTP proxy on port 4321:

    curl --proxy http://proxy.example.org:4321 https://remote.example.org/

## Username and password

Some services are setup to require HTTP authentication and then you need to
provide name and password which is then transferred to the remote site in
various ways depending on the exact authentication protocol used.

You can opt to either insert the user and password in the URL or you can
provide them separately:

    curl https://user:password@example.org/

or

    curl -u user:password https://example.org/

You need to pay attention that this kind of HTTP authentication is not what
is usually done and requested by user-oriented websites these days. They tend
to use forms and cookies instead.

## Path part

The path part is sent off to the server to request that it sends back the
associated response. The path is what is to the right side of the slash that
follows the hostname and possibly port number.

# Fetch a page

## GET

The simplest and most common request/operation made using HTTP is to GET a
URL. The URL could itself refer to a webpage, an image or a file. The client
issues a GET request to the server and receives the document it asked for.
If you issue the command line

    curl https://curl.se/

you get a webpage returned in your terminal window. The entire HTML document
this URL identifies.

All HTTP replies contain a set of response headers that are normally hidden,
use curl's [`--include`](https://curl.se/docs/manpage.html#-i) (`-i`)
option to display them as well as the rest of the document.

## HEAD

You can ask the remote server for ONLY the headers by using the
[`--head`](https://curl.se/docs/manpage.html#-I) (`-I`) option which makes
curl issue a HEAD request. In some special cases servers deny the HEAD method
while others still work, which is a particular kind of annoyance.

The HEAD method is defined and made so that the server returns the headers
exactly the way it would do for a GET, but without a body. It means that you
may see a `Content-Length:` in the response headers, but there must not be an
actual body in the HEAD response.

## Multiple URLs in a single command line

A single curl command line may involve one or many URLs. The most common case
is probably to use one, but you can specify any amount of URLs. Yes any. No
limits. You then get requests repeated over and over for all the given URLs.

Example, send two GET requests:

    curl https://url1.example.com https://url2.example.com

If you use [`--data`](https://curl.se/docs/manpage.html#-d) to POST to
the URL, using multiple URLs means that you send that same POST to all the
given URLs.

Example, send two POSTs:

    curl --data name=curl https://url1.example.com https://url2.example.com

## Multiple HTTP methods in a single command line

Sometimes you need to operate on several URLs in a single command line and do
different HTTP methods on each. For this, you might enjoy the
[`--next`](https://curl.se/docs/manpage.html#-:) option. It is a separator
that separates a bunch of options from the next. All the URLs before `--next`
get the same method and get all the POST data merged into one.

When curl reaches the `--next` on the command line, it resets the method and
the POST data and allow a new set.

Perhaps this is best shown with a few examples. To send first a HEAD and then
a GET:

    curl -I https://example.com --next https://example.com

To first send a POST and then a GET:

    curl -d score=10 https://example.com/post.cgi --next https://example.com/results.html

# HTML forms

## Forms explained

Forms are the general way a website can present an HTML page with fields for
the user to enter data in, and then press some kind of 'OK' or 'Submit'
button to get that data sent to the server. The server then typically uses
the posted data to decide how to act. Like using the entered words to search
in a database, or to add the info in a bug tracking system, display the
entered address on a map or using the info as a login-prompt verifying that
the user is allowed to see what it is about to see.

Of course there has to be some kind of program on the server end to receive
the data you send. You cannot invent something out of the air.

## GET

A GET-form uses the method GET, as specified in HTML like:

```html
<form method="GET" action="junk.cgi">
  <input type=text name="birthyear">
  <input type=submit name=press value="OK">
</form>
```

In your favorite browser, this form appears with a text box to fill in and a
press-button labeled "OK". If you fill in '1905' and press the OK button,
your browser then creates a new URL to get for you. The URL gets
`junk.cgi?birthyear=1905&press=OK` appended to the path part of the previous
URL.

If the original form was seen on the page `www.example.com/when/birth.html`,
the second page you get becomes
`www.example.com/when/junk.cgi?birthyear=1905&press=OK`.

Most search engines work this way.

To make curl do the GET form post for you, enter the expected created URL:

    curl "https://www.example.com/when/junk.cgi?birthyear=1905&press=OK"

## POST

The GET method makes all input field names get displayed in the URL field of
your browser. That is generally a good thing when you want to be able to
bookmark that page with your given data, but it is an obvious disadvantage if
you entered secret information in one of the fields or if there are a large
amount of fields creating a long and unreadable URL.

The HTTP protocol then offers the POST method. This way the client sends the
data separated from the URL and thus you do not see any of it in the URL
address field.

The form would look similar to the previous one:

```html
<form method="POST" action="junk.cgi">
  <input type=text name="birthyear">
  <input type=submit name=press value=" OK ">
</form>
```

To use curl to post this form with the same data filled in as before, we
could do it like:

    curl --data "birthyear=1905&press=%20OK%20" https://www.example.com/when/junk.cgi

This kind of POST uses the Content-Type `application/x-www-form-urlencoded`
and is the most widely used POST kind.

The data you send to the server MUST already be properly encoded, curl does
not do that for you. For example, if you want the data to contain a space,
you need to replace that space with `%20`, etc. Failing to comply with this
most likely causes your data to be received wrongly and messed up.

Recent curl versions can in fact URL encode POST data for you, like this:

    curl --data-urlencode "name=I am Daniel" https://www.example.com

If you repeat `--data` several times on the command line, curl concatenates
all the given data pieces - and put a `&` symbol between each data segment.

## File Upload POST

Back in late 1995 they defined an additional way to post data over HTTP. It
is documented in the RFC 1867, why this method sometimes is referred to as
RFC 1867-posting.

This method is mainly designed to better support file uploads. A form that
allows a user to upload a file could be written like this in HTML:

    <form method="POST" enctype='multipart/form-data' action="upload.cgi">
      <input name=upload type=file>
      <input type=submit name=press value="OK">
    </form>

This clearly shows that the Content-Type about to be sent is
`multipart/form-data`.

To post to a form like this with curl, you enter a command line like:

    curl --form upload=@localfilename --form press=OK [URL]

## Hidden Fields

A common way for HTML based applications to pass state information between
pages is to add hidden fields to the forms. Hidden fields are already filled
in, they are not displayed to the user and they get passed along as all the
other fields.

A similar example form with one visible field, one hidden field and one
submit button could look like:

```html
<form method="POST" action="foobar.cgi">
  <input type=text name="birthyear">
  <input type=hidden name="person" value="daniel">
  <input type=submit name="press" value="OK">
</form>
```

To POST this with curl, you do not have to think about if the fields are
hidden or not. To curl they are all the same:

    curl --data "birthyear=1905&press=OK&person=daniel" [URL]

## Figure Out What A POST Looks Like

When you are about to fill in a form and send it to a server by using curl
instead of a browser, you are of course interested in sending a POST exactly
the way your browser does.

An easy way to get to see this, is to save the HTML page with the form on
your local disk, modify the 'method' to a GET, and press the submit button
(you could also change the action URL if you want to).

You then clearly see the data get appended to the URL, separated with a
`?`-letter as GET forms are supposed to.

# HTTP upload

## PUT

Perhaps the best way to upload data to an HTTP server is to use PUT. Then
again, this of course requires that someone put a program or script on the
server end that knows how to receive an HTTP PUT stream.

Put a file to an HTTP server with curl:

    curl --upload-file uploadfile https://www.example.com/receive.cgi

# HTTP Authentication

## Basic Authentication

HTTP Authentication is the ability to tell the server your username and
password so that it can verify that you are allowed to do the request you are
doing. The Basic authentication used in HTTP (which is the type curl uses by
default) is **plain text** based, which means it sends username and password
only slightly obfuscated, but still fully readable by anyone that sniffs on
the network between you and the remote server.

To tell curl to use a user and password for authentication:

    curl --user myname:password https://www.example.com

## Other Authentication

The site might require a different authentication method (check the headers
returned by the server), and then
[`--ntlm`](https://curl.se/docs/manpage.html#--ntlm),
[`--digest`](https://curl.se/docs/manpage.html#--digest),
[`--negotiate`](https://curl.se/docs/manpage.html#--negotiate) or even
[`--anyauth`](https://curl.se/docs/manpage.html#--anyauth) might be
options that suit you.

## Proxy Authentication

Sometimes your HTTP access is only available through the use of an HTTP
proxy. This seems to be especially common at various companies. An HTTP proxy
may require its own user and password to allow the client to get through to
the Internet. To specify those with curl, run something like:

    curl --proxy-user proxyuser:proxypassword curl.se

If your proxy requires the authentication to be done using the NTLM method,
use [`--proxy-ntlm`](https://curl.se/docs/manpage.html#--proxy-ntlm), if
it requires Digest use
[`--proxy-digest`](https://curl.se/docs/manpage.html#--proxy-digest).

If you use any one of these user+password options but leave out the password
part, curl prompts for the password interactively.

## Hiding credentials

Do note that when a program is run, its parameters might be possible to see
when listing the running processes of the system. Thus, other users may be
able to watch your passwords if you pass them as plain command line
options. There are ways to circumvent this.

It is worth noting that while this is how HTTP Authentication works, many
websites do not use this concept when they provide logins etc. See the Web
Login chapter further below for more details on that.

# More HTTP Headers

## Referer

An HTTP request may include a 'referer' field (yes it is misspelled), which
can be used to tell from which URL the client got to this particular
resource. Some programs/scripts check the referer field of requests to verify
that this was not arriving from an external site or an unknown page. While
this is a stupid way to check something so easily forged, many scripts still
do it. Using curl, you can put anything you want in the referer-field and
thus more easily be able to fool the server into serving your request.

Use curl to set the referer field with:

    curl --referer https://www.example.come https://www.example.com

## User Agent

Similar to the referer field, all HTTP requests may set the User-Agent
field. It names what user agent (client) that is being used. Many
applications use this information to decide how to display pages. Silly web
programmers try to make different pages for users of different browsers to
make them look the best possible for their particular browsers. They usually
also do different kinds of JavaScript etc.

At times, you may learn that getting a page with curl does not return the
same page that you see when getting the page with your browser. Then you know
it is time to set the User Agent field to fool the server into thinking you
are one of those browsers.

By default, curl uses curl/VERSION, such as User-Agent: curl/8.11.0.

To make curl look like Internet Explorer 5 on a Windows 2000 box:

    curl --user-agent "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)" [URL]

Or why not look like you are using Netscape 4.73 on an old Linux box:

    curl --user-agent "Mozilla/4.73 [en] (X11; U; Linux 2.2.15 i686)" [URL]

## Redirects

## Location header

When a resource is requested from a server, the reply from the server may
include a hint about where the browser should go next to find this page, or a
new page keeping newly generated output. The header that tells the browser to
redirect is `Location:`.

curl does not follow `Location:` headers by default, but displays such
pages in the same manner it displays all HTTP replies. It does however
feature an option that makes it attempt to follow the `Location:` pointers.

To tell curl to follow a Location:

    curl --location https://www.example.com

If you use curl to POST to a site that immediately redirects you to another
page, you can safely use [`--location`](https://curl.se/docs/manpage.html#-L)
(`-L`) and `--data`/`--form` together. curl only uses POST in the first
request, and then revert to GET in the following operations.

## Other redirects

Browsers typically support at least two other ways of redirects that curl
does not: first the html may contain a meta refresh tag that asks the browser
to load a specific URL after a set number of seconds, or it may use
JavaScript to do it.

# Cookies

## Cookie Basics

The way the web browsers do "client side state control" is by using cookies.
Cookies are names with associated contents. The cookies are sent to the client
by the server. The server tells the client for what path and hostname it wants
the cookie sent back, and it also sends an expiration date and a few more
properties.

When a client communicates with a server with a name and path as previously
specified in a received cookie, the client sends back the cookies and their
contents to the server, unless of course they are expired.

Many applications and servers use this method to connect a series of requests
into a single logical session. To be able to use curl in such occasions, we
must be able to record and send back cookies the way the web application
expects them. The same way browsers deal with them.

## Cookie options

The simplest way to send a few cookies to the server when getting a page with
curl is to add them on the command line like:

    curl --cookie "name=Daniel" https://www.example.com

Cookies are sent as common HTTP headers. This is practical as it allows curl
to record cookies by recording headers. Record cookies with curl by
using the [`--dump-header`](https://curl.se/docs/manpage.html#-D) (`-D`)
option like:

    curl --dump-header headers_and_cookies https://www.example.com

(Take note that the
[`--cookie-jar`](https://curl.se/docs/manpage.html#-c) option described
below is a better way to store cookies.)

curl has a full blown cookie parsing engine built-in that comes in use if you
want to reconnect to a server and use cookies that were stored from a
previous connection (or hand-crafted manually to fool the server into
believing you had a previous connection). To use previously stored cookies,
you run curl like:

    curl --cookie stored_cookies_in_file https://www.example.com

curl's "cookie engine" gets enabled when you use the
[`--cookie`](https://curl.se/docs/manpage.html#-b) option. If you only
want curl to understand received cookies, use `--cookie` with a file that
does not exist. Example, if you want to let curl understand cookies from a
page and follow a location (and thus possibly send back cookies it received),
you can invoke it like:

    curl --cookie nada --location https://www.example.com

curl has the ability to read and write cookie files that use the same file
format that Netscape and Mozilla once used. It is a convenient way to share
cookies between scripts or invokes. The `--cookie` (`-b`) switch
automatically detects if a given file is such a cookie file and parses it,
and by using the `--cookie-jar` (`-c`) option you make curl write a new
cookie file at the end of an operation:

    curl --cookie cookies.txt --cookie-jar newcookies.txt \
      https://www.example.com

# HTTPS

## HTTPS is HTTP secure

There are a few ways to do secure HTTP transfers. By far the most common
protocol for doing this is what is generally known as HTTPS, HTTP over
SSL. SSL encrypts all the data that is sent and received over the network and
thus makes it harder for attackers to spy on sensitive information.

SSL (or TLS as the current version of the standard is called) offers a set of
advanced features to do secure transfers over HTTP.

curl supports encrypted fetches when built to use a TLS library and it can be
built to use one out of a fairly large set of libraries - `curl -V` shows
which one your curl was built to use (if any). To get a page from an HTTPS
server, run curl like:

    curl https://secure.example.com

## Certificates

In the HTTPS world, you use certificates to validate that you are the one you
claim to be, as an addition to normal passwords. curl supports client- side
certificates. All certificates are locked with a passphrase, which you need
to enter before the certificate can be used by curl. The passphrase can be
specified on the command line or if not, entered interactively when curl
queries for it. Use a certificate with curl on an HTTPS server like:

    curl --cert mycert.pem https://secure.example.com

curl also tries to verify that the server is who it claims to be, by
verifying the server's certificate against a locally stored CA cert bundle.
Failing the verification causes curl to deny the connection. You must then
use [`--insecure`](https://curl.se/docs/manpage.html#-k) (`-k`) in case you
want to tell curl to ignore that the server cannot be verified.

More about server certificate verification and CA cert bundles can be read in
the [`SSLCERTS` document](https://curl.se/docs/sslcerts.html).

At times you may end up with your own CA cert store and then you can tell
curl to use that to verify the server's certificate:

    curl --cacert ca-bundle.pem https://example.com/

# Custom Request Elements

## Modify method and headers

Doing fancy stuff, you may need to add or change elements of a single curl
request.

For example, you can change the POST method to `PROPFIND` and send the data
as `Content-Type: text/xml` (instead of the default `Content-Type`) like
this:

    curl --data "<xml>" --header "Content-Type: text/xml" \
      --request PROPFIND example.com

You can delete a default header by providing one without content. Like you
can ruin the request by chopping off the `Host:` header:

    curl --header "Host:" https://www.example.com

You can add headers the same way. Your server may want a `Destination:`
header, and you can add it:

    curl --header "Destination: nowhere" https://example.com

## More on changed methods

It should be noted that curl selects which methods to use on its own
depending on what action to ask for. `-d` makes a POST, `-I` makes a HEAD and
so on. If you use the [`--request`](https://curl.se/docs/manpage.html#-X) /
`-X` option you can change the method keyword curl selects, but you do not
modify curl's behavior. This means that if you for example use -d "data" to
do a POST, you can modify the method to a `PROPFIND` with `-X` and curl still
thinks it sends a POST. You can change the normal GET to a POST method by
adding `-X POST` in a command line like:

    curl -X POST https://example.org/

curl however still acts as if it sent a GET so it does not send any request
body etc.

# Web Login

## Some login tricks

While not strictly HTTP related, it still causes a lot of people problems so
here's the executive run-down of how the vast majority of all login forms work
and how to login to them using curl.

It can also be noted that to do this properly in an automated fashion, you
most certainly need to script things and do multiple curl invokes etc.

First, servers mostly use cookies to track the logged-in status of the
client, so you need to capture the cookies you receive in the responses.
Then, many sites also set a special cookie on the login page (to make sure
you got there through their login page) so you should make a habit of first
getting the login-form page to capture the cookies set there.

Some web-based login systems feature various amounts of JavaScript, and
sometimes they use such code to set or modify cookie contents. Possibly they
do that to prevent programmed logins, like this manual describes how to...
Anyway, if reading the code is not enough to let you repeat the behavior
manually, capturing the HTTP requests done by your browsers and analyzing the
sent cookies is usually a working method to work out how to shortcut the
JavaScript need.

In the actual `<form>` tag for the login, lots of sites fill-in
random/session or otherwise secretly generated hidden tags and you may need
to first capture the HTML code for the login form and extract all the hidden
fields to be able to do a proper login POST. Remember that the contents need
to be URL encoded when sent in a normal POST.

# Debug

## Some debug tricks

Many times when you run curl on a site, you notice that the site does not
seem to respond the same way to your curl requests as it does to your
browser's.

Then you need to start making your curl requests more similar to your
browser's requests:

- Use the `--trace-ascii` option to store fully detailed logs of the requests
  for easier analyzing and better understanding

- Make sure you check for and use cookies when needed (both reading with
  `--cookie` and writing with `--cookie-jar`)

- Set user-agent (with [`-A`](https://curl.se/docs/manpage.html#-A)) to
  one like a recent popular browser does

- Set referer (with [`-E`](https://curl.se/docs/manpage.html#-E)) like
  it is set by the browser

- If you use POST, make sure you send all the fields and in the same order as
  the browser does it.

## Check what the browsers do

A good helper to make sure you do this right, is the web browsers' developers
tools that let you view all headers you send and receive (even when using
HTTPS).

A more raw approach is to capture the HTTP traffic on the network with tools
such as Wireshark or tcpdump and check what headers that were sent and
received by the browser. (HTTPS forces you to use `SSLKEYLOGFILE` to do
that.)
<!--
Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.

SPDX-License-Identifier: curl
-->

# TODO intro

Things to do in project curl. Please tell us what you think, contribute and
send us patches that improve things.

Be aware that these are things that we could do, or have once been considered
things we could do. If you want to work on any of these areas, please consider
bringing it up for discussions first on the mailing list so that we all agree
it is still a good idea for the project.

All bugs documented in the [known_bugs
document](https://curl.se/docs/knownbugs.html) are subject for fixing.

# libcurl

## `struct lifreq`

Use `struct lifreq` and `SIOCGLIFADDR` instead of `struct ifreq` and
`SIOCGIFADDR` on newer Solaris versions as they claim the latter is obsolete.
To support IPv6 interface addresses for network interfaces properly.

## alt-svc sharing

The share interface could benefit from allowing the alt-svc cache to be
possible to share between easy handles.

See [curl issue 4476](https://github.com/curl/curl/issues/4476)

The share interface offers CURL_LOCK_DATA_CONNECT to have multiple easy
handle share a connection cache, but due to how connections are used they are
still not thread-safe when used shared.

See [curl issue 4915](https://github.com/curl/curl/issues/4915) and lib1541.c

The share interface offers CURL_LOCK_DATA_HSTS to have multiple easy handle
share an HSTS cache, but this is not thread-safe.

## thread-safe sharing

Using the share interface users can share some data between easy handles but
several of the sharing options are documented as not safe and supported to
share between multiple concurrent threads. Fixing this would enable more users
to share data in more powerful ways.

## updated DNS server while running

If `/etc/resolv.conf` gets updated while a program using libcurl is running, it
may cause name resolves to fail unless `res_init()` is called. We should
consider calling `res_init()` + retry once unconditionally on all name resolve
failures to mitigate against this. Firefox works like that. Note that Windows
does not have `res_init()` or an alternative.

[curl issue 2251](https://github.com/curl/curl/issues/2251)

## c-ares and CURLOPT_OPENSOCKETFUNCTION

curl creates most sockets via the CURLOPT_OPENSOCKETFUNCTION callback and
close them with the CURLOPT_CLOSESOCKETFUNCTION callback. c-ares does not use
those functions and instead opens and closes the sockets itself. This means
that when curl passes the c-ares socket to the CURLMOPT_SOCKETFUNCTION it is
not owned by the application like other sockets.

See [curl issue 2734](https://github.com/curl/curl/issues/2734)

## Monitor connections in the connection pool

libcurl's connection cache or pool holds a number of open connections for the
purpose of possible subsequent connection reuse. It may contain a few up to a
significant amount of connections. Currently, libcurl leaves all connections
as they are and first when a connection is iterated over for matching or reuse
purpose it is verified that it is still alive.

Those connections may get closed by the server side for idleness or they may
get an HTTP/2 ping from the peer to verify that they are still alive. By
adding monitoring of the connections while in the pool, libcurl can detect
dead connections (and close them) better and earlier, and it can handle HTTP/2
pings to keep such ones alive even when not actively doing transfers on them.

## Try to URL encode given URL

Given a URL that for example contains spaces, libcurl could have an option
that would try somewhat harder than it does now and convert spaces to %20 and
perhaps URL encoded byte values over 128 etc (do what the redirect following
code already does).

[curl issue 514](https://github.com/curl/curl/issues/514)

## Add support for IRIs

IRIs (RFC 3987) allow localized, non-ASCII, names in the URL. To properly
support this, curl/libcurl would need to translate/encode the given input
from the input string encoding into percent encoded output "over the wire".

To make that work smoothly for curl users even on Windows, curl would probably
need to be able to convert from several input encodings.

## try next proxy if one does not work

Allow an application to specify a list of proxies to try, and failing to
connect to the first go on and try the next instead until the list is
exhausted. Browsers support this feature at least when they specify proxies
using `PAC`.

[curl issue 896](https://github.com/curl/curl/issues/896)

## provide timing info for each redirect

curl and libcurl provide timing information via a set of different time-stamps
(CURLINFO_*_TIME). When curl is following redirects, those returned time value
are the accumulated sums. An improvement could be to offer separate timings
for each redirect.

[curl issue 6743](https://github.com/curl/curl/issues/6743)

## CURLINFO_PAUSE_STATE

Return information about the transfer's current pause state, in both
directions. See [curl issue 2588](https://github.com/curl/curl/issues/2588)

## Expose tried IP addresses that failed

When libcurl fails to connect to a host, it could offer the application the
addresses that were used in the attempt. Source + destination IP, source +
destination port and protocol (UDP or TCP) for each failure. Possibly as a
callback. Perhaps also provide reason.

[curl issue 2126](https://github.com/curl/curl/issues/2126)

## erase secrets from heap/stack after use

Introducing a concept and system to erase secrets from memory after use, it
could help mitigate and lessen the impact of (future) security problems etc.
However: most secrets are passed to libcurl as clear text from the application
and then clearing them within the library adds nothing...

[curl issue 7268](https://github.com/curl/curl/issues/7268)

## make DoH inherit more transfer properties

Some options are not inherited because they are not relevant for the DoH SSL
connections, or inheriting the option may result in unexpected behavior. For
example the user's debug function callback is not inherited because it would
be unexpected for internal handles (i.e DoH handles) to be passed to that
callback.

If an option is not inherited then it is not possible to set it separately
for DoH without a DoH-specific option. For example:
`CURLOPT_DOH_SSL_VERIFYHOST`, `CURLOPT_DOH_SSL_VERIFYPEER` and
`CURLOPT_DOH_SSL_VERIFYSTATUS`.

See [curl issue 6605](https://github.com/curl/curl/issues/6605)

# libcurl - multi interface

## More non-blocking

Make sure we do not ever loop because of non-blocking sockets returning
`EWOULDBLOCK` or similar. Blocking cases include:

- Name resolves on non-Windows unless c-ares or the threaded resolver is used.
- The threaded resolver may block on cleanup:
  [curl issue 4852](https://github.com/curl/curl/issues/4852)
- `file://` transfers
- TELNET transfers
- GSSAPI authentication for FTP transfers
- The "DONE" operation (post transfer protocol-specific actions) for the
protocols SFTP, SMTP, FTP. Fixing `multi_done()` for this is a worthy task.
- `curl_multi_remove_handle()` for any of the above.
- Calling `curl_ws_send()` from a callback

## Better support for same name resolves

If a name resolve has been initiated for a given name and a second easy handle
wants to resolve that same name as well, make it wait for the first resolve to
end up in the cache instead of doing a second separate resolve. This is
especially needed when adding many simultaneous handles using the same
hostname when the DNS resolver can get flooded.

## Non-blocking `curl_multi_remove_handle()`

The multi interface has a few API calls that assume a blocking behavior, like
`add_handle()` and `remove_handle()` which limits what we can do internally.
The multi API need to be moved even more into a single function that "drives"
everything in a non-blocking manner and signals when something is done. A
remove or add would then only ask for the action to get started and then
`multi_perform()` etc still be called until the add/remove is completed.

## Split connect and authentication process

The multi interface treats the authentication process as part of the connect
phase. As such any failures during authentication does not trigger the
relevant QUIT or LOGOFF for protocols such as IMAP, POP3 and SMTP.

## Edge-triggered sockets should work

The multi_socket API should work with edge-triggered socket events. One of the
internal actions that need to be improved for this to work perfectly is the
`maxloops` handling in `transfer.c:readwrite_data()`.

## multi upkeep

In libcurl 7.62.0 we introduced `curl_easy_upkeep`. It unfortunately only
works on easy handles. We should introduces a version of that for the multi
handle, and also consider doing `upkeep` automatically on connections in the
connection pool when the multi handle is in used.

See [curl issue 3199](https://github.com/curl/curl/issues/3199)

## Virtual external sockets

libcurl performs operations on the given file descriptor that presumes it is a
socket and an application cannot replace them at the moment. Allowing an
application to fully replace those would allow a larger degree of freedom and
flexibility.

See [curl issue 5835](https://github.com/curl/curl/issues/5835)

## dynamically decide to use socketpair

For users who do not use `curl_multi_wait()` or do not care for
`curl_multi_wakeup()`, we could introduce a way to make libcurl NOT create a
socketpair in the multi handle.

See [curl issue 4829](https://github.com/curl/curl/issues/4829)

# Documentation

## Improve documentation about fork safety

See [curl issue 6968](https://github.com/curl/curl/issues/6968)

# FTP

## A fixed directory listing format

Since listing the contents of a remove directory with FTP is returning the
list in a format and style the server likes without any established or even
defacto standard existing, it would be a feature to users if curl could parse
the directory listing and output a general curl format that is fixed and the
same, independent of the server's choice. This would allow users to better and
more reliably extract information about remote content via FTP directory
listings.

## GSSAPI via Windows SSPI

In addition to currently supporting the SASL GSSAPI mechanism (Kerberos V5)
via third-party GSS-API libraries, such as MIT Kerberos, also add support for
GSSAPI authentication via Windows SSPI.

## STAT for LIST without data connection

Some FTP servers allow STAT for listing directories instead of using LIST, and
the response is then sent over the control connection instead of as the
otherwise used data connection.

This is not detailed in any FTP specification.

## Passive transfer could try other IP addresses

When doing FTP operations through a proxy at localhost, the reporter spotted
that curl only tried to connect once to the proxy, while it had multiple
addresses and a failed connect on one address should make it try the next.

After switching to passive mode (EPSV), curl could try all IP addresses for
`localhost`. Currently it tries `::1`, but it should also try `127.0.0.1`.

See [curl issue 1508](https://github.com/curl/curl/issues/1508)

# HTTP

## Provide the error body from a CONNECT response

When curl receives a body response from a CONNECT request to a proxy, it
always reads and ignores it. It would make some users happy if curl instead
optionally would be able to make that response available. Via a new callback?
Through some other means?

See [curl issue 9513](https://github.com/curl/curl/issues/9513)

## Obey `Retry-After` in redirects

The `Retry-After` response header is said to dictate "the minimum time that
the user agent is asked to wait before issuing the redirected request" and
libcurl does not obey this.

See [curl issue 11447](https://github.com/curl/curl/issues/11447)

## Rearrange request header order

Server implementers often make an effort to detect browser and to reject
clients it can detect to not match. One of the last details we cannot yet
control in libcurl's HTTP requests, which also can be exploited to detect that
libcurl is in fact used even when it tries to impersonate a browser, is the
order of the request headers. I propose that we introduce a new option in
which you give headers a value, and then when the HTTP request is built it
sorts the headers based on that number. We could then have internally created
headers use a default value so only headers that need to be moved have to be
specified.

## Allow SAN names in HTTP/2 server push

curl only allows HTTP/2 push promise if the provided :authority header value
exactly matches the hostname given in the URL. It could be extended to allow
any name that would match the Subject Alternative Names in the server's TLS
certificate.

See [curl pull request 3581](https://github.com/curl/curl/pull/3581)

## `auth=` in URLs

Add the ability to specify the preferred authentication mechanism to use by
using `;auth=<mech>` in the login part of the URL.

For example:

`http://test:pass;auth=NTLM@example.com` would be equivalent to specifying
`--user test:pass;auth=NTLM` or `--user test:pass --ntlm` from the command
line.

Additionally this should be implemented for proxy base URLs as well.

## Require HTTP version X or higher

curl and libcurl provide options for trying higher HTTP versions (for example
HTTP/2) but then still allows the server to pick version 1.1. We could
consider adding a way to require a minimum version.

See [curl issue 7980](https://github.com/curl/curl/issues/7980)

# TELNET

## ditch stdin

Reading input (to send to the remote server) on stdin is a crappy solution for
library purposes. We need to invent a good way for the application to be able
to provide the data to send.

## ditch telnet-specific select

Move the telnet support's network `select()` loop go away and merge the code
into the main transfer loop. Until this is done, the multi interface does not
work for telnet.

## feature negotiation debug data

Add telnet feature negotiation data to the debug callback as header data.

## exit immediately upon connection if stdin is /dev/null

If it did, curl could be used to probe if there is an server there listening
on a specific port. That is, the following command would exit immediately
after the connection is established with exit code 0:

    curl -s --connect-timeout 2 telnet://example.com:80 </dev/null

# SMTP

## Pass NOTIFY option to CURLOPT_MAIL_RCPT

Is there a way to pass the NOTIFY option to the CURLOPT_MAIL_RCPT option ? I
set a string that already contains a bracket. For instance something like
that: `curl_slist_append(recipients, "<foo@bar> NOTIFY=SUCCESS,FAILURE");`.

[curl issue 8232](https://github.com/curl/curl/issues/8232)

## Enhanced capability support

Add the ability, for an application that uses libcurl, to obtain the list of
capabilities returned from the EHLO command.

## Add `CURLOPT_MAIL_CLIENT` option

Rather than use the URL to specify the mail client string to present in the
`HELO` and `EHLO` commands, libcurl should support a new `CURLOPT`
specifically for specifying this data as the URL is non-standard and to be
honest a bit of a hack.

Please see the following thread for more information:
https://curl.se/mail/lib-2012-05/0178.html

# POP3

## Enhanced capability support

Add the ability, for an application that uses libcurl, to obtain the list of
capabilities returned from the CAPA command.

# IMAP

## Enhanced capability support

Add the ability, for an application that uses libcurl, to obtain the list of
capabilities returned from the CAPABILITY command.

# LDAP

## SASL based authentication mechanisms

Currently the LDAP module only supports `ldap_simple_bind_s()` in order to
bind to an LDAP server. This function sends username and password details
using the simple authentication mechanism (as clear text). It should be
possible to use `ldap_bind_s()` instead specifying the security context
information ourselves.

## `CURLOPT_SSL_CTX_FUNCTION` for LDAPS

`CURLOPT_SSL_CTX_FUNCTION` works perfectly for HTTPS and email protocols, but
it has no effect for LDAPS connections.

[curl issue 4108](https://github.com/curl/curl/issues/4108)

## Paged searches on LDAP server

[curl issue 4452](https://github.com/curl/curl/issues/4452)

## Certificate-Based Authentication

LDAPS not possible with macOS and Windows with Certificate-Based Authentication

[curl issue 9641](https://github.com/curl/curl/issues/9641)

# WebSocket

## Support text frames with command line tool

libcurl defaults to using binary WebSocket frames, which makes some servers
not work as they require text. We should make it possible to tell the tool to
use text frames.

[curl issue 21997](https://github.com/curl/curl/issues/21997)

An abandoned attempt to add support for this exists in [PR
22093](https://github.com/curl/curl/pull/22093).

# TLS

## `TLS-PSK` with OpenSSL

Transport Layer Security pre-shared key cipher suites (`TLS-PSK`) is a set of
cryptographic protocols that provide secure communication based on pre-shared
keys (`PSK`). These pre-shared keys are symmetric keys shared in advance among
the communicating parties.

[curl issue 5081](https://github.com/curl/curl/issues/5081)

## TLS channel binding

TLS 1.2 and 1.3 provide the ability to extract some secret data from the TLS
connection and use it in the client request (usually in some sort of
authentication) to ensure that the data sent is bound to the specific TLS
connection and cannot be successfully intercepted by a proxy. This
functionality can be used in a standard authentication mechanism such as
GSS-API or SCRAM, or in custom approaches like custom HTTP Authentication
headers.

For TLS 1.2, the binding type is usually `tls-unique`, and for TLS 1.3 it is
`tls-exporter`.

- https://datatracker.ietf.org/doc/html/rfc5929
- https://datatracker.ietf.org/doc/html/rfc9266
- [curl issue 9226](https://github.com/curl/curl/issues/9226)

## Defeat TLS fingerprinting

By changing the order of TLS extensions provided in the TLS handshake, it is
sometimes possible to circumvent TLS fingerprinting by servers. The TLS
extension order is of course not the only way to fingerprint a client.

## Less memory massaging with Schannel

The Schannel backend does a lot of custom memory management we would rather
avoid: the repeated allocation + free in sends and the custom memory + realloc
system for encrypted and decrypted data. That should be avoided and reduced
for 1) efficiency and 2) safety.

## Support DANE

[DNS-Based Authentication of Named Entities
(DANE)](https://datatracker.ietf.org/doc/html/rfc6698) is a way to provide
SSL keys and certs over DNS using DNSSEC as an alternative to the CA model.

A patch was posted on March 7 2013
(https://curl.se/mail/lib-2013-03/0075.html) but it was a too simple approach.
See Daniel's comments: https://curl.se/mail/lib-2013-03/0103.html

Björn Stenberg once wrote a separate initial take on DANE that was never
completed.

## TLS record padding

TLS (1.3) offers optional record padding and OpenSSL provides an API for it. I
could make sense for libcurl to offer this ability to applications to make
traffic patterns harder to figure out by network traffic observers.

See [curl issue 5398](https://github.com/curl/curl/issues/5398)

## Support Authority Information Access certificate extension (AIA)

AIA can provide various things like certificate revocation lists but more
importantly information about intermediate CA certificates that can allow
validation path to be fulfilled when the HTTPS server does not itself provide
them.

Since AIA is about downloading certs on demand to complete a TLS handshake, it
is probably a bit tricky to get done right and a serious privacy leak.

See [curl issue 2793](https://github.com/curl/curl/issues/2793)

## Some TLS options are not offered for HTTPS proxies

Some TLS related options to the command line tool and libcurl are only
provided for the server and not for HTTPS proxies. `--proxy-tls-max`,
`--proxy-tlsv1.3`, `--proxy-curves` and a few more. For more Documentation on
this see: https://curl.se/libcurl/c/tls-options.html

[curl issue 12286](https://github.com/curl/curl/issues/12286)

## Make sure we forbid TLS 1.3 post-handshake authentication

RFC 8740 explains how using HTTP/2 must forbid the use of TLS 1.3
post-handshake authentication. We should make sure to live up to that.

See [curl issue 5396](https://github.com/curl/curl/issues/5396)

## Support the `clienthello` extension

Certain stupid networks and middle boxes have a problem with SSL handshake
packets that are within a certain size range because how that sets some bits
that previously (in older TLS version) were not set. The `clienthello`
extension adds padding to avoid that size range.

- https://datatracker.ietf.org/doc/html/rfc7685
- [curl issue 2299](https://github.com/curl/curl/issues/2299)

## Share the CA cache

For TLS backends that supports CA caching, it makes sense to allow the share
object to be used to store the CA cache as well via the share API. Would allow
multiple easy handles to reuse the CA cache and save themselves from a lot of
extra processing overhead.

## Add missing features to TLS backends

The feature matrix at https://curl.se/libcurl/c/tls-options.html shows which
features are supported by which TLS backends, and thus also where there are
feature gaps.

## ECH for QUIC

curl's support for ECH is currently limited to TCP only.

# Proxy

## Retry SOCKS handshake on address type not supported

When curl resolves a hostname, it might get a mix of IPv6 and IPv4 returned.
curl might then use an IPv6 address with a SOCKS5 proxy, which - if it does
not support IPv6 - returns "Address type not supported" and curl exits with
that error.

Perhaps it is preferred if curl would in this situation instead first retry
the SOCKS handshake again for this case and then use one of the IPv4 addresses
for the target host.

See [curl issue 17222](https://github.com/curl/curl/issues/17222)

# Schannel

## Extend support for client certificate authentication

The existing support for the `-E`/`--cert` and `--key` options could be
extended by supplying a custom certificate and key in PEM format, see:
[Getting a Certificate for
Schannel](https://learn.microsoft.com/windows/win32/secauthn/getting-a-certificate-for-schannel)

## Extend support for the `--ciphers` option

The existing support for the `--ciphers` option could be extended by mapping
the OpenSSL/GnuTLS cipher suites to the Schannel APIs, see [Specifying
Schannel Ciphers and Cipher
Strengths](https://learn.microsoft.com/windows/win32/secauthn/specifying-schannel-ciphers-and-cipher-strengths).

## Add option to allow abrupt server closure

libcurl with Schannel errors without a known termination point from the server
(such as length of transfer, or SSL "close notify" alert) to prevent against a
truncation attack. Really old servers may neglect to send any termination
point. An option could be added to ignore such abrupt closures.

[curl issue 4427](https://github.com/curl/curl/issues/4427)

# SASL

## Other authentication mechanisms

Add support for other authentication mechanisms such as `OLP`, `GSS-SPNEGO`
and others.

## Add `QOP` support to GSSAPI authentication

Currently the GSSAPI authentication only supports the default `QOP` of auth
(Authentication), whilst Kerberos V5 supports both `auth-int` (Authentication
with integrity protection) and `auth-conf` (Authentication with integrity and
privacy protection).

# SSH protocols

## Multiplexing

SSH is a perfectly fine multiplexed protocols which would allow libcurl to do
multiple parallel transfers from the same host using the same connection, much
in the same spirit as HTTP/2 does. libcurl however does not take advantage of
that ability but does instead always create a new connection for new transfers
even if an existing connection already exists to the host.

To fix this, libcurl would have to detect an existing connection and "attach"
the new transfer to the existing one.

## Handle growing SFTP files

The SFTP code in libcurl checks the file size *before* a transfer starts and
then proceeds to transfer exactly that amount of data. If the remote file
grows while the transfer is in progress libcurl does not notice and does not
adapt. The OpenSSH SFTP command line tool does and libcurl could also attempt
to download more to see if there is more to get...

[curl issue 4344](https://github.com/curl/curl/issues/4344)

## Read keys from `~/.ssh/id_ecdsa`, `id_ed25519`

The libssh2 backend in curl is limited to only reading keys from `id_rsa` and
`id_dsa`, which makes it fail connecting to servers that use more modern key
types.

[curl issue 8586](https://github.com/curl/curl/issues/8586)

## Support `CURLOPT_PREQUOTE`

The two other `QUOTE` options are supported for SFTP, but this was left out
for unknown reasons.

## SSH over HTTPS proxy for libssh

The SSH based protocols SFTP and SCP did not work over HTTPS proxy at all
until [curl pull request 6021](https://github.com/curl/curl/pull/6021) brought
the functionality with the libssh2 backend. Presumably, this support can/could
be added for the libssh backend as well.

## SFTP with `scp://`

OpenSSH 9 switched their `scp` tool to speak SFTP under the hood. Going
forward it might be worth having curl or libcurl attempt SFTP if SCP fails to
follow suite.

# Command line tool

## multi-threading

When asked to do transfers in parallel, the curl tool could be extended to use
a number of independent worker threads. This would allow faster transfers in
situations where curl becomes CPU bound.

Ideally, curl would (with permission) fire up new threads on demand when it
deems that it might be helpful. Perhaps, if it has more transfers to add and
the existing transfers make the CPU busy enough and there are more cores
available.

## sync

`curl --sync http://example.com/feed[1-100].rss` or
`curl --sync http://example.net/{index,calendar,history}.html`

Downloads a range or set of URLs using the remote name, but only if the remote
file is newer than the local file. A `Last-Modified` HTTP date header should
also be used to set the mod date on the downloaded file.

## glob posts

Globbing support for `-d` and `-F`, as in `curl -d "name=foo[0-9]" URL`. This
is easily scripted though.

## `--proxycommand`

Allow the user to make curl run a command and use its stdio to make requests
and not do any network connection by itself. Example:

    curl --proxycommand 'ssh pi@raspberrypi.local -W 10.1.1.75 80' \
      http://some/otherwise/unavailable/service.php

See [curl issue 4941](https://github.com/curl/curl/issues/4941)

## UTF-8 filenames in Content-Disposition

RFC 6266 documents how UTF-8 names can be passed to a client in the
`Content-Disposition` header, and curl does not support this.

[curl issue 1888](https://github.com/curl/curl/issues/1888)

## Option to make `-Z` merge line-based outputs on stdout

When a user requests multiple line-based files using `-Z` and sends them to
stdout, curl does not *merge* and send complete lines but may send
partial lines from several sources.

[curl issue 5175](https://github.com/curl/curl/issues/5175)

## specify which response codes that make `-f`/`--fail` return error

Allows a user to better specify exactly which error code(s) that are fine and
which are errors for their specific uses cases

## Choose the name of file in braces for complex URLs

When using braces to download a list of URLs and you use complicated names
in the list of alternatives, it could be handy to allow curl to use other
names when saving.

Consider a way to offer that. Possibly like
`{partURL1:name1,partURL2:name2,partURL3:name3}` where the name following the
colon is the output name.

See [curl issue 221](https://github.com/curl/curl/issues/221)

## improve how curl works in a Windows console window

If you pull the scroll bar when transferring with curl in a Windows console
window, the transfer is interrupted and can get disconnected. This can
probably be improved. See [curl issue 322](https://github.com/curl/curl/issues/322)

## Windows: set attribute 'archive' for completed downloads

The archive bit (`FILE_ATTRIBUTE_ARCHIVE, 0x20`) separates files that shall be
backed up from those that are either not ready or have not changed.

Downloads in progress are neither ready to be backed up, nor should they be
opened by a different process. Only after a download has been completed it is
sensible to include it in any incremental snapshot or backup of the system.

See [curl issue 3354](https://github.com/curl/curl/issues/3354)

## keep running, read instructions from pipe/socket

Provide an option that makes curl not exit after the last URL (or even work
without a given URL), and then make it read instructions passed on a pipe or
over a socket to make further instructions so that a second subsequent curl
invoke can talk to the still running instance and ask for transfers to get
done, and thus maintain its connection pool, DNS cache and more.

## Acknowledge `Ratelimit` headers

Consider a command line option that can make curl do multiple serial requests
while acknowledging server specified [rate
limits](https://datatracker.ietf.org/doc/html/draft-ietf-httpapi-ratelimit-headers/).

See [curl issue 5406](https://github.com/curl/curl/issues/5406)

## `--dry-run`

A command line option that makes curl show exactly what it would do and send
if it would run for real.

See [curl issue 5426](https://github.com/curl/curl/issues/5426)

## `--retry` should resume

When `--retry` is used and curl actually retries transfer, it should use the
already transferred data and do a resumed transfer for the rest (when
possible) so that it does not have to transfer the same data again that was
already transferred before the retry.

See [curl issue 1084](https://github.com/curl/curl/issues/1084)

## retry on network is unreachable

The `--retry` option retries transfers on *transient failures*. We later added
`--retry-connrefused` to also retry for *connection refused* errors.

Suggestions have been brought to also allow retry on *network is unreachable*
errors and while totally reasonable, maybe we should consider a way to make
this more configurable than to add a new option for every new error people
want to retry for?

[curl issue 1603](https://github.com/curl/curl/issues/1603)

## hostname sections in config files

config files would be more powerful if they could set different configurations
depending on used URLs, hostname or possibly origin. Then a default `.curlrc`
could a specific user-agent only when doing requests against a certain site.

## retry on the redirected-to URL

When curl is told to `--retry` a failed transfer and follows redirects, it
might get an HTTP 429 response from the redirected-to URL and not the original
one, which then could make curl decide to rather retry the transfer on that
URL only instead of the original operation to the original URL.

Perhaps extra emphasized if the original transfer is a large POST that
redirects to a separate GET, and that GET is what gets the 429

See [curl issue 5462](https://github.com/curl/curl/issues/5462)

## Set the modification date on an uploaded file

For SFTP and possibly FTP, curl could offer an option to set the modification
time for the uploaded file.

See [curl issue 5768](https://github.com/curl/curl/issues/5768)

## Use multiple parallel transfers for a single download

To enhance transfer speed, downloading a single URL can be split up into
multiple separate range downloads that get combined into a single final
result.

An ideal implementation would not use a specified number of parallel
transfers, but curl could:
- First start getting the full file as transfer A
- If after N seconds have passed and the transfer is expected to continue for
  M seconds or more, add a new transfer (B) that asks for the second half of
  A's content (and stop A at the middle).
- If splitting up the work improves the transfer rate, it could then be done
  again. Then again, etc up to a limit.

This way, if transfer B fails (because Range: is not supported) it lets
transfer A remain the single one. N and M could be set to some sensible
defaults.

See [curl issue 5774](https://github.com/curl/curl/issues/5774)

## Prevent terminal injection when writing to terminal

curl could offer an option to make escape sequence either non-functional or
avoid cursor moves or similar to reduce the risk of a user getting tricked by
clever tricks.

See [curl issue 6150](https://github.com/curl/curl/issues/6150)

## `-J` and `-O` with %-encoded filenames

`-J`/`--remote-header-name` does not decode %-encoded filenames. RFC 6266
details how it should be done. The can of worm is that we have no charset
handling in curl and ASCII >=128 is a challenge for us. Not to mention that
decoding also means that we need to check for nastiness that is attempted,
like `../` sequences and the like. Probably everything to the left of any
embedded slashes should be cut off. See https://curl.se/bug/view.cgi?id=1294

`-O` also does not decode %-encoded names, and while it has even less
information about the charset involved the process is similar to the `-J`
case.

Note that we do not decode `-O` without the user asking for it with some other
means, since `-O` has always been documented to use the name exactly as
specified in the URL.

## `-J` with `-C -`

When using `-J` (with `-O`), automatically resumed downloading together with
`-C -` fails. Without `-J` the same command line works. This happens because
the resume logic is worked out before the target filename (and thus its
pre-transfer size) has been figured out. This can be improved.

https://curl.se/bug/view.cgi?id=1169

## `--retry` and transfer timeouts

If using `--retry` and the transfer timeouts (possibly due to using -m or
`-y`/`-Y`) the next attempt does not resume the transfer properly from what
was downloaded in the previous attempt but truncates and restarts at the
original position where it was at before the previous failed attempt. See
https://curl.se/mail/lib-2008-01/0080.html

# Build

## Enable `PIE` and `RELRO` by default

Especially when having programs that execute curl via the command line, `PIE`
renders the exploitation of memory corruption vulnerabilities a lot more
difficult. This can be attributed to the additional information leaks being
required to conduct a successful attack. `RELRO`, on the other hand, masks
different binary sections like the `GOT` as read-only and thus kills a handful
of techniques that come in handy when attackers are able to arbitrarily
overwrite memory. A few tests showed that enabling these features had close to
no impact, neither on the performance nor on the general functionality of
curl.

## Do not use GNU libtool on OpenBSD

When compiling curl on OpenBSD with `--enable-debug` it gives linking errors
when you use GNU libtool. This can be fixed by using the libtool provided by
OpenBSD itself. However for this the user always needs to invoke make with
`LIBTOOL=/usr/bin/libtool`. It would be nice if the script could have some
logic to detect if this system is an OpenBSD host and then use the OpenBSD
libtool instead.

See [curl issue 5862](https://github.com/curl/curl/issues/5862)

## Package curl for Windows in a signed installer

See [curl issue 5424](https://github.com/curl/curl/issues/5424)

## make configure use `--cache-file` more and better

The configure script can be improved to cache more values so that repeated
invokes run much faster.

See [curl issue 7753](https://github.com/curl/curl/issues/7753)

# Test suite

## SSL tunnel

Make our own version of stunnel for simple port forwarding to enable HTTPS and
FTP-SSL tests without the stunnel dependency, and it could allow us to provide
test tools built with either OpenSSL or GnuTLS

## more protocols supported

Extend the test suite to include more protocols. The telnet could do FTP or
http operations (for which we have test servers).

## more platforms supported

Make the test suite work on more platforms. OpenBSD and macOS. Remove fork()s
and it should become even more portable.

## write an SMB test server to replace impacket

This would allow us to run SMB tests on more platforms and do better and more
covering tests.

See [curl issue 15697](https://github.com/curl/curl/issues/15697)

## Use the RFC 6265 test suite

A test suite made for HTTP cookies (RFC 6265) by Adam Barth [is
available](https://github.com/abarth/http-state/tree/master/tests).

It would be good if someone would write a script/setup that would run curl
with that test suite and detect deviance. Ideally, that would even be
incorporated into our regular test suite.

## Run web-platform-tests URL tests

Run web-platform-tests URL tests and compare results with browsers on
`wpt.fyi`.

It would help us find issues to fix and help us document where our parser
differs from the WHATWG URL spec parsers.

See [curl issue 4477](https://github.com/curl/curl/issues/4477)

# MQTT

## Support rate-limiting

The rate-limiting logic is done in the PERFORMING state in multi.c but MQTT is
not (yet) implemented to use that.

## Handle network blocks

Running test suite with `CURL_DBG_SOCK_WBLOCK=90 ./runtests.pl -a mqtt` makes
several MQTT test cases fail where they should not.

## large payloads

libcurl unnecessarily allocates heap memory to hold the entire payload to get
sent, when the data is already perfectly accessible where it is when
`CURLOPT_POSTFIELDS` is used. This is highly inefficient for larger payloads.
Additionally, libcurl does not support using the read callback for sending
MQTT which is yet another way to avoid having to hold large payload in memory.

# TFTP

## TFTP does not convert LF to CRLF for `mode=netascii`

RFC 3617 defines that an TFTP transfer can be done using `netascii` mode. curl
does not support extracting that mode from the URL nor does it treat such
transfers specifically. It should probably do LF to CRLF translations for
them.

See [curl issue 12655](https://github.com/curl/curl/issues/12655)

# Gopher

## Handle network blocks

Running test suite with `CURL_DBG_SOCK_WBLOCK=90 ./runtests.pl -a 1200 to
1300` makes several Gopher test cases fail where they should not.
<!--
Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.

SPDX-License-Identifier: curl
-->

# URL syntax and their use in curl

## Specifications

The official "URL syntax" is primarily defined in these two different
specifications:

- [RFC 3986](https://datatracker.ietf.org/doc/html/rfc3986) (although URL is
  called "URI" in there)
- [The WHATWG URL Specification](https://url.spec.whatwg.org/)

RFC 3986 is the earlier one, and curl has always tried to adhere to that one
(since it shipped in January 2005).

The WHATWG URL spec was written later, is incompatible with the RFC 3986 and
changes over time.

## Variations

URL parsers as implemented in browsers, libraries and tools usually opt to
support one of the mentioned specifications. Bugs, differences in
interpretations and the moving nature of the WHATWG spec does however make it
unlikely that multiple parsers treat URLs the same way.

## Security

Due to the inherent differences between URL parser implementations, it is
considered a security risk to mix different implementations and assume the
same behavior.

For example, if you use one parser to check if a URL uses a good hostname or
the correct auth field, and then pass on that same URL to a *second* parser,
there is always a risk it treats the same URL differently. There is no right
and wrong in URL land, only differences of opinions.

libcurl offers a separate API to its URL parser for this reason, among others.

Applications may at times find it convenient to allow users to specify URLs
for various purposes and that string would then end up fed to curl. Getting a
URL from an external untrusted party and using it with curl brings several
security concerns:

1. If you have an application that runs as or in a server application, getting
   an unfiltered URL can trick your application to access a local resource
   instead of a remote resource. Protecting yourself against localhost accesses
   is hard when accepting user provided URLs.

2. Such custom URLs can access other ports than you planned as port numbers
   are part of the regular URL format. The combination of a local host and a
   custom port number can allow external users to play tricks with your local
   services.

3. Such a URL might use other schemes than you thought of or planned for.

## "RFC 3986 plus"

curl recognizes a URL syntax that we call "RFC 3986 plus". It is grounded on
the well established RFC 3986 to make sure previously written command lines
and curl using scripts remain working.

curl's URL parser allows a few deviations from the spec in order to
inter-operate better with URLs that appear in the wild.

### Spaces

A URL provided to curl cannot contain spaces. They need to be provided URL
encoded to be accepted in a URL by curl.

An exception to this rule: `Location:` response headers that indicate to a
client where a resource has been redirected to, sometimes contain spaces. This
is a violation of RFC 3986 but is fine in the WHATWG spec. curl handles these
by re-encoding them to `%20`.

### Non-ASCII

Byte values in a provided URL that are outside of the printable ASCII range
are percent-encoded by curl.

### Multiple slashes

An absolute URL always starts with a "scheme" followed by a colon. For all the
schemes curl supports, the colon must be followed by two slashes according to
RFC 3986 but not according to the WHATWG spec - which allows one to infinity
amount.

curl allows one, two or three slashes after the colon to still be considered a
valid URL.

### "scheme-less"

curl supports "URLs" that do not start with a scheme. This is not supported by
any of the specifications. This is a shortcut to entering URLs that was
supported by browsers early on and has been mimicked by curl.

Based on what the hostname starts with, curl "guesses" what protocol to use:

- `ftp.` means FTP
- `dict.` means DICT
- `ldap.` means LDAP
- `imap.` means IMAP
- `smtp.` means SMTP
- `pop3.` means POP3
- all other means HTTP

### Globbing letters

The curl command line tool supports "globbing" of URLs. It means that you can
create ranges and lists using `[N-M]` and `{one,two,three}` sequences. The
letters used for this (`[]{}`) are reserved in RFC 3986 and can therefore not
legitimately be part of such a URL.

They are however not reserved or special in the WHATWG specification, so
globbing can mess up such URLs. Globbing can be turned off for such occasions
(using `--globoff`).

# URL syntax details

A URL may consist of the following components - many of them are optional:

    [scheme][divider][userinfo][hostname][port number][path][query][fragment]

Each component is separated from the following component with a divider
character or string.

For example, this could look like:

    https://user:password@www.example.com:80/index.html?foo=bar#top

## Scheme

The scheme specifies the protocol to use. A curl build can support a few or
many different schemes. You can limit what schemes curl should accept.

curl supports the following schemes on URLs specified to transfer. They are
matched case insensitively:

`dict`, `file`, `ftp`, `ftps`, `gopher`, `gophers`, `http`, `https`, `imap`,
`imaps`, `ldap`, `ldaps`, `mqtt`, `pop3`, `pop3s`, `rtsp`, `smb`, `smbs`,
`smtp`, `smtps`, `telnet`, `tftp`

When the URL is specified to identify a proxy, curl recognizes the following
schemes:

`http`, `https`, `socks4`, `socks4a`, `socks5`, `socks5h`, `socks`

## Userinfo

The userinfo field can be used to set username and password for authentication
purposes in this transfer. The use of this field is discouraged since it often
means passing around the password in plain text and is thus a security risk.

URLs for IMAP, POP3 and SMTP also support *login options* as part of the
userinfo field. They are provided as a semicolon after the password and then
the options.

## Hostname

The hostname part of the URL contains the address of the server that you want
to connect to. This can be the fully qualified domain name of the server, the
local network name of the machine on your network or the IP address of the
server or machine represented by either an IPv4 or IPv6 address (within
brackets). For example:

    https://www.example.com/

    https://hostname.example/

    https://192.168.0.1/

    https://[2001:1890:1112:1::20]/

libcurl rejects hostnames with more than one trailing dot.

### Numerical IPv4 addresses

libcurl parses and normalizes everything that appears to be a numerical IPv4
address. Including octal and hexadecimal formats and using one, two, three or
four number groups.

This normalizing is done so that curl can properly get documents from HTTP
servers (with the correctly formatted address in the `Host:` header), so that
IP based filtering for things like the `NO_PROXY` environment variable has a
higher chance of working correctly, to increase the chances that two URLs can
be compared and to allow users to extract and visualize the address in a readable
way and to make sure libcurl works identically across different name resolver
libraries and function calls.

For a hostname that is only an IPv4 address with a trailing dot, the trailing
dot is removed in the normalizing process.

### Numerical IPv6 addresses

libcurl allows a zone id to be provided with a numerical IPv6 address,
separated with a percent character (`%`). The percent character may also be
percent-encoded as `%25`. Like this:

    http://[fe80::1%25eth0]/

    http://[fe80::1%eth0]/

### `IPvFuture`

RFC 3986 documents a numerical IP address format called `IPvFuture`. libcurl
does not recognize this format. Using it causes parse errors.

### "localhost"

Starting in curl 7.77.0, curl uses loopback IP addresses for the name
`localhost`: `127.0.0.1` and `::1`. It does not resolve the name using the
resolver functions.

This is done to make sure the host accessed is truly the localhost - the local
machine.

### IDNA

If curl was built with International Domain Name (IDN) support, it can also
handle hostnames using non-ASCII characters.

When built with libidn2, curl uses the IDNA 2008 standard. This is equivalent
to the WHATWG URL spec, but differs from certain browsers that use IDNA 2003
Transitional Processing. The two standards have a huge overlap but differ
slightly, perhaps most famously in how they deal with the
[German "double s"](https://en.wikipedia.org/wiki/%c3%9f).

When WinIDN is used, curl uses IDNA 2003 Transitional Processing, like the rest
of Windows.

## Port number

If there is a colon after the hostname, that should be followed by the port
number to use. 1 - 65535. curl also supports a blank port number field - but
only if the URL starts with a scheme.

If the port number is not specified in the URL, curl uses a default port
number based on the provide scheme:

DICT 2628, FTP 21, FTPS 990, GOPHER 70, GOPHERS 70, HTTP 80, HTTPS 443, IMAP
143, IMAPS 993, LDAP 389, LDAPS 636, MQTT 1883, POP3 110, POP3S 995, RTSP 554,
SCP 22, SFTP 22, SMB 445, SMBS 445, SMTP 25, SMTPS 465, TELNET 23, TFTP 69

## Path

By default, libcurl removes sequences of `/./` and `/../` from the path as per
RFC 3986.

libcurl might also normalize percent-encoded sequences to use uppercase
hexadecimal letters.

# Scheme specific behaviors

## FTP

The path part of an FTP request specifies the file to retrieve and from which
directory. If the file part is omitted then libcurl downloads the directory
listing for the directory specified. If the directory is omitted then the
directory listing for the root / home directory is returned.

FTP servers typically put the user in its "home directory" after login, which
then differs between users. To explicitly specify the root directory of an FTP
server, start the path with double slash `//` or `/%2f` (2F is the hexadecimal
value of the ASCII code for the slash).

## FILE

When a `file://` URL is accessed on Windows systems, it can be crafted in a
way so that Windows attempts to connect to a (remote) machine when curl wants
to read or write such a path.

curl only allows the hostname part of a FILE URL to be one out of these three
alternatives: `localhost`, `127.0.0.1` or blank ("", zero characters).
Anything else makes curl fail to parse the URL.

### Windows-specific FILE details

curl accepts that the FILE URL's path starts with a "drive letter". That is a
single letter `a` to `z` followed by a colon or a pipe character (`|`).

The Windows operating system itself converts some file accesses to perform
network accesses over SMB/CIFS, through several different file path patterns.
This way, a `file://` URL passed to curl *might* be converted into a network
access inadvertently and unknowingly to curl. This is a Windows feature curl
cannot control or disable.

## IMAP

The path part of an IMAP request not only specifies the mailbox to list or
select, but can also be used to check the `UIDVALIDITY` of the mailbox, to
specify the `UID`, `SECTION` and `PARTIAL` octets of the message to fetch and
to specify what messages to search for.

A top level folder list:

    imap://user:password@mail.example.com

A folder list on the user's inbox:

    imap://user:password@mail.example.com/INBOX

Select the user's inbox and fetch message with `uid = 1`:

    imap://user:password@mail.example.com/INBOX/;UID=1

Select the user's inbox and fetch the first message in the mail box:

    imap://user:password@mail.example.com/INBOX/;MAILINDEX=1

Select the user's inbox, check the `UIDVALIDITY` of the mailbox is 50 and
fetch message 2 if it is:

    imap://user:password@mail.example.com/INBOX;UIDVALIDITY=50/;UID=2

Select the user's inbox and fetch the text portion of message 3:

    imap://user:password@mail.example.com/INBOX/;UID=3/;SECTION=TEXT

Select the user's inbox and fetch the first 1024 octets of message 4:

    imap://user:password@mail.example.com/INBOX/;UID=4/;PARTIAL=0.1024

Select the user's inbox and check for NEW messages:

    imap://user:password@mail.example.com/INBOX?NEW

Select the user's inbox and search for messages containing "shadows" in the
subject line:

    imap://user:password@mail.example.com/INBOX?SUBJECT%20shadows

Searching via the query part of the URL `?` is a search request for the
results to be returned as message sequence numbers (`MAILINDEX`). It is
possible to make a search request for results to be returned as unique ID
numbers (`UID`) by using a custom curl request via `-X`. `UID` numbers are
unique per session (and multiple sessions when `UIDVALIDITY` is the same). For
example, if you are searching for `"foo bar"` in header+body (`TEXT`) and you
want the matching `MAILINDEX` numbers returned then you could search via URL:

    imap://user:password@mail.example.com/INBOX?TEXT%20%22foo%20bar%22

If you want matching `UID` numbers you have to use a custom request:

    imap://user:password@mail.example.com/INBOX -X "UID SEARCH TEXT \"foo bar\""

For more information about IMAP commands please see RFC 9051. For more
information about the individual components of an IMAP URL please see RFC 5092.

* Note old curl versions would `FETCH` by message sequence number when `UID`
was specified in the URL. That was a bug fixed in 7.62.0, which added
`MAILINDEX` to `FETCH` by mail sequence number.

## LDAP

The path part of an LDAP request can be used to specify the: Distinguished
Name, Attributes, Scope, Filter and Extension for an LDAP search. Each field
is separated by a question mark and when that field is not required an empty
string with the question mark separator should be included.

Search for the `DN` as `My Organization`:

    ldap://ldap.example.com/o=My%20Organization

the same search but only return `postalAddress` attributes:

    ldap://ldap.example.com/o=My%20Organization?postalAddress

Search for an empty `DN` and request information about the
`rootDomainNamingContext` attribute for an Active Directory server:

    ldap://ldap.example.com/?rootDomainNamingContext

For more information about the individual components of an LDAP URL please see
[RFC 4516](https://datatracker.ietf.org/doc/html/rfc4516).

## POP3

The path part of a POP3 request specifies the message ID to retrieve. If the
ID is not specified then a list of waiting messages is returned instead.

## SCP

The path part of an SCP URL specifies the path and file to retrieve or
upload. The file is taken as an absolute path from the root directory on the
server.

To specify a path relative to the user's home directory on the server, prepend
`~/` to the path portion.

## SFTP

The path part of an SFTP URL specifies the file to retrieve or upload. If the
path ends with a slash (`/`) then a directory listing is returned instead of a
file. If the path is omitted entirely then the directory listing for the root
/ home directory is returned.

## SMB
The path part of an SMB request specifies the file to retrieve and from what
share and directory or the share to upload to and as such, may not be omitted.
If the username is embedded in the URL then it must contain the domain name
and as such, the backslash must be URL encoded as %2f.

When uploading to SMB, the size of the file needs to be known ahead of time,
meaning that you can upload a file passed to curl over a pipe like stdin.

curl supports SMB version 1 (only)

## SMTP

The path part of an SMTP request specifies the hostname to present during
communication with the mail server. If the path is omitted, then libcurl
attempts to resolve the local computer's hostname. This may not return the
fully qualified domain name that is required by some mail servers and
specifying this path allows you to set an alternative name, such as your
machine's fully qualified domain name, which you might have obtained from an
external function such as gethostname or getaddrinfo.

The default smtp port is 25. Some servers use port 587 as an alternative.
<!--
Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.

SPDX-License-Identifier: curl
-->

# Verify

Do not trust, verify!

## Signed releases

Every curl release is shipped as a set of tarballs. They all have the exact
same content but use different archivers, visible by the different file
extensions used.

Each tarball is signed by the curl release manager Daniel. The digital
signatures for each tarball are always provided. The digital signatures can be
used to verify that the tarballs were produced by Daniel.

If the curl website were breached and fake curl releases were
provided, they could be detected using these signatures.

Daniel's public GPG key: [27ED EAF2 2F3A BCEB 50DB 9A12 5CC9 08FD B71E 12C2](https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x27edeaf22f3abceb50db9a125cc908fdb71e12c2)

## Reproducible releases

The curl project ships *reproducible releases*. This means that everyone is
able - and encouraged - to independently verify the contents of every curl
release. Verify that it contains exactly the bits that are supposed to be in
the release and nothing extra.

The curl releases are generated using a Docker image to make it easy to get an
identical setup. To verify an existing curl release, we provide a convenient
script that generates a new curl release from source code and then compares
this newly generated release tarball with the tarball file you downloaded from
curl.se.

For full verification, invoke the script inside an up-to-date curl source code
git repository. Without a git repository present, it does a lighter check by
rebuilding the release using the files in the tarball.

Note: full verification mode checks out the release tag in your repository.
Run it in a clean working tree (no local changes) or a dedicated clone.

Invoke it like this:

    git clone https://github.com/curl/curl
    cd curl
    mv [download-dir]/curl-8.19.0.tar.xz .
    ./scripts/verify-release curl-8.19.0.tar.xz

A successful check ends up with a final output similar to:

    curl-8.19.0.tar.xz: OK

By verifying the release tarballs, you verify that Daniel does not infect the
release on purpose or involuntarily because of anything malicious running in
his setup.

### Verify the verify

Of course you should not blindly trust the verification script. It is short
and simple and should be quick to verify. Or you write your own script that
you trust, to do the same job.

## Source code

How do you then verify that what is in git is fine to build a product from?

In the curl project we verify the source code in multiple ways, and one way to
gain trust is to verify and review our testing procedures.

- we have a consistent code style (invalid style causes errors)

- we ban and avoid a number of "sensitive" and "hard-to-use" C functions (use
  of such functions causes errors)

- we have a ceiling for complexity in functions to keep them easy to follow,
  read and understand (failing to do so causes errors)

- we review all pull requests before merging, both with humans and with bots.
  We link back commits to their origin pull requests in commit messages.

- we ban use of "binary blobs" in git to not provide means for malicious
  actors to bundle encrypted payloads (trying to include a blob causes errors)

- every single file in the git repository has a clear copyright and license
  statement. Complete knowledge and tracking of provenience.

- we actively avoid base64 encoded chunks as they too could function as ways
  to obfuscate malicious contents

- we forbid and prevent git force push on the master branch. History cannot be
  rewritten.

- we ban most uses of UTF-8 in code and documentation to avoid easily mixed
  up Unicode characters that look like other characters. (adding Unicode
  characters causes errors)

- we document everything to make it clear how things are supposed to work. No
  surprises. Lots of documentation is tested and verified in addition to
  spellchecks and consistent wording.

- we have thousands of tests and we add test cases for (ideally) every
  functionality. Finding "white spots" and adding coverage is a top priority.
  curl runs on countless operating systems, CPU architectures and you can
  build curl in billions of different configuration setups: not every
  combination is practically possible to test

- we build curl and run tests in over two hundred CI jobs that are run for
  every commit and every PR. We do not merge commits that have unexplained
  test failures.

- we run all tests as "torture tests", where each test case is rerun to have
  every invoked fallible function call fail once each, to make sure curl
  never leaks memory or crashes due to this.

- we build curl in CI with the most picky compiler options enabled and we
  never allow compiler warnings to linger. We always use `-Werror` that
  converts warnings to errors and fail the builds.

- we run all tests using valgrind and several combinations of sanitizers to
  find and reduce the risk for memory problems, undefined behavior and
  similar

- we keep running static code analyzers on the code, both traditional ones
  (clang-tidy, CodeSonar, Coverity) but also new generation AI powered ones
  like Zeropath and Codex Security.

- we run fuzzing on curl: non-stop as part of Google's OSS-Fuzz project, but
  also briefly as part of the CI setup for every commit and PR

- we make sure that the CI jobs we have for curl never "write back" to curl.
  They access the source repository read-only and even if they would be
  breached, they cannot infect or taint source code.

- we run `zizmor` and other code analyzer tools on the CI job config scripts
  to reduce the risk of us running or using insecure CI jobs.

- we do reproducible releases to allow anyone to verify that the contents is
  untainted

- we digitally sign releases, git tags and git commits

- there is a git backup on [codeberg](https://codeberg.org/curl/) for enhanced
  resilience to infrastructure disturbance

- we are committed to always fix reported vulnerabilities in the following
  release. Security problems never linger around once they have been
  reported.

- we document everything and every detail about all curl vulnerabilities ever
  reported

- our code has been audited several times by external security experts, and
  the few issues that have been detected in those were immediately addressed

- Strong two-factor authentication on GitHub is mandatory for all committers

- our commitment to never breaking ABI or API allows all users to easily
  upgrade to new releases. This enables users to run recent security-fixed
  versions instead of legacy insecure versions.

- we have a vulnerability disclosure program that allows researchers to submit
  suspected vulnerabilities in a private and secure fashion, so that we can
  work on fixing curl and announcing the flaw in a responsible manner to
  minimize risks for users.
<!--
Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.

SPDX-License-Identifier: curl
-->

# Version Numbers and Releases

The command line tool curl and the library libcurl are individually
versioned, but they usually follow each other closely.

The version numbering is always built up using the same system:

       X.Y.Z

- X is main version number
- Y is release number
- Z is patch number

## Bumping numbers

One of these numbers get bumped in each new release. The numbers to the right
of a bumped number are reset to zero.

The main version number is bumped when *really* big, world colliding changes
are made. The release number is bumped when changes are performed or
things/features are added. The patch number is bumped when the changes are
mere bugfixes.

It means that after release 1.2.3, we can release 2.0.0 if something really
big has been made, 1.3.0 if not that big changes were made or 1.2.4 if only
bugs were fixed.

Bumping, as in increasing the number with 1, is unconditionally only affecting
one of the numbers (except the ones to the right of it, that may be set to
zero). 1 becomes 2, 3 becomes 4, 9 becomes 10, 88 becomes 89 and 99
becomes 100. After 1.2.9 comes 1.2.10. After 3.99.3, 3.100.0 might come.

All original curl source release archives are named according to the libcurl
version (not according to the curl client version that, as said before, might
differ).

As a service to any application that might want to support new libcurl
features while still being able to build with older versions, all releases
have the libcurl version stored in the `curl/curlver.h` file using a static
numbering scheme that can be used for comparison. The version number is
defined as:

```c
#define LIBCURL_VERSION_NUM 0xXXYYZZ
```

Where `XX`, `YY` and `ZZ` are the main version, release and patch numbers in
hexadecimal. All three number fields are always represented using two digits
(eight bits each). 1.2 would appear as "0x010200" while version 9.11.7
appears as `0x090b07`.

This 6-digit hexadecimal number is always a greater number in a more recent
release. It makes comparisons with greater than and less than work.

This number is also available as three separate defines:
`LIBCURL_VERSION_MAJOR`, `LIBCURL_VERSION_MINOR` and `LIBCURL_VERSION_PATCH`.

## Past releases

This is a list of all public releases with their version numbers and release
dates. The tool was called `httpget` before 2.0, `urlget` before 4.0 then
`curl` since 4.0. `libcurl` and `curl` are always released in sync, using the
same version numbers.

- 8.23.0: pending
- 8.22.0: September 2, 2026
- 8.21.0: June 24 2026
- 8.20.0: April 29 2026
- 8.19.0: March 11 2026
- 8.18.0: January 7 2026
- 8.17.0: November 5 2025
- 8.16.0: September 10 2025
- 8.15.0: July 16 2025
- 8.14.1: June 4 2025
- 8.14.0: May 28 2025
- 8.13.0: April 2 2025
- 8.12.1: February 13 2025
- 8.12.0: February 5 2025
- 8.11.1: December 11 2024
- 8.11.0: November 6 2024
- 8.10.1: September 18 2024
- 8.10.0: September 11 2024
- 8.9.1: July 31 2024
- 8.9.0: July 24 2024
- 8.8.0: May 22 2024
- 8.7.1: March 27 2024
- 8.7.0: March 27 2024
- 8.6.0: January 31 2024
- 8.5.0: December 6 2023
- 8.4.0: October 11 2023
- 8.3.0: September 13 2023
- 8.2.1: July 26 2023
- 8.2.0: July 19 2023
- 8.1.2: May 30 2023
- 8.1.1: May 23 2023
- 8.1.0: May 17 2023
- 8.0.1: March 20 2023
- 8.0.0: March 20 2023
- 7.88.1: February 20 2023
- 7.88.0: February 15 2023
- 7.87.0: December 21 2022
- 7.86.0: October 26 2022
- 7.85.0: August 31 2022
- 7.84.0: June 27 2022
- 7.83.1: May 11 2022
- 7.83.0: April 27 2022
- 7.82.0: March 5 2022
- 7.81.0: January 5 2022
- 7.80.0: November 10 2021
- 7.79.1: September 22 2021
- 7.79.0: September 15 2021
- 7.78.0: July 21 2021
- 7.77.0: May 26 2021
- 7.76.1: April 14 2021
- 7.76.0: March 31 2021
- 7.75.0: February 3 2021
- 7.74.0: December 9 2020
- 7.73.0: October 14 2020
- 7.72.0: August 19 2020
- 7.71.1: July 1 2020
- 7.71.0: June 24 2020
- 7.70.0: April 29 2020
- 7.69.1: March 11 2020
- 7.69.0: March 4 2020
- 7.68.0: January 8 2020
- 7.67.0: November 6 2019
- 7.66.0: September 11 2019
- 7.65.3: July 19 2019
- 7.65.2: July 17 2019
- 7.65.1: June 5 2019
- 7.65.0: May 22 2019
- 7.64.1: March 27 2019
- 7.64.0: February 6 2019
- 7.63.0: December 12 2018
- 7.62.0: October 31 2018
- 7.61.1: September 5 2018
- 7.61.0: July 11 2018
- 7.60.0: May 16 2018
- 7.59.0: March 14 2018
- 7.58.0: January 24 2018
- 7.57.0: November 29 2017
- 7.56.1: October 23 2017
- 7.56.0: October 4 2017
- 7.55.1: August 14 2017
- 7.55.0: August 9 2017
- 7.54.1: June 14 2017
- 7.54.0: April 19 2017
- 7.53.1: February 24 2017
- 7.53.0: February 22 2017
- 7.52.1: December 23 2016
- 7.52.0: December 21 2016
- 7.51.0: November 2 2016
- 7.50.3: September 14 2016
- 7.50.2: September 7 2016
- 7.50.1: August 3 2016
- 7.50.0: July 21 2016
- 7.49.1: May 30 2016
- 7.49.0: May 18 2016
- 7.48.0: March 23 2016
- 7.47.1: February 8 2016
- 7.47.0: January 27 2016
- 7.46.0: December 2 2015
- 7.45.0: October 7 2015
- 7.44.0: August 12 2015
- 7.43.0: June 17 2015
- 7.42.1: April 29 2015
- 7.42.0: April 22 2015
- 7.41.0: February 25 2015
- 7.40.0: January 8 2015
- 7.39.0: November 5 2014
- 7.38.0: September 10 2014
- 7.37.1: July 16 2014
- 7.37.0: May 21 2014
- 7.36.0: March 26 2014
- 7.35.0: January 29 2014
- 7.34.0: December 17 2013
- 7.33.0: October 14 2013
- 7.32.0: August 12 2013
- 7.31.0: June 22 2013
- 7.30.0: April 12 2013
- 7.29.0: February 6 2013
- 7.28.1: November 20 2012
- 7.28.0: October 10 2012
- 7.27.0: July 27 2012
- 7.26.0: May 24 2012
- 7.25.0: March 22 2012
- 7.24.0: January 24 2012
- 7.23.1: November 17 2011
- 7.23.0: November 15 2011
- 7.22.0: September 13 2011
- 7.21.7: June 23 2011
- 7.21.6: April 22 2011
- 7.21.5: April 17 2011
- 7.21.4: February 17 2011
- 7.21.3: December 15 2010
- 7.21.2: October 13 2010
- 7.21.1: August 11 2010
- 7.21.0: June 16 2010
- 7.20.1: April 14 2010
- 7.20.0: February 9 2010
- 7.19.7: November 4 2009
- 7.19.6: August 12 2009
- 7.19.5: May 18 2009
- 7.19.4: March 3 2009
- 7.19.3: January 19 2009
- 7.19.2: November 13 2008
- 7.19.1: November 5 2008
- 7.19.0: September 1 2008
- 7.18.2: June 4 2008
- 7.18.1: March 30 2008
- 7.18.0: January 28 2008
- 7.17.1: October 29 2007
- 7.17.0: September 13 2007
- 7.16.4: July 10 2007
- 7.16.3: June 25 2007
- 7.16.2: April 11 2007
- 7.16.1: January 29 2007
- 7.16.0: October 30 2006
- 7.15.5: August 7 2006
- 7.15.4: June 12 2006
- 7.15.3: March 20 2006
- 7.15.2: February 27 2006
- 7.15.1: December 7 2005
- 7.15.0: October 13 2005
- 7.14.1: September 1 2005
- 7.14.0: May 16 2005
- 7.13.2: April 4 2005
- 7.13.1: March 4 2005
- 7.13.0: February 1 2005
- 7.12.3: December 20 2004
- 7.12.2: October 18 2004
- 7.12.1: August 10 2004
- 7.12.0: June 2 2004
- 7.11.2: April 26 2004
- 7.11.1: March 19 2004
- 7.11.0: January 22 2004
- 7.10.8: November 1 2003
- 7.10.7: August 15 2003
- 7.10.6: July 28 2003
- 7.10.5: May 19 2003
- 7.10.4: April 2 2003
- 7.10.3: January 14 2003
- 7.10.2: November 18 2002
- 7.10.1: October 11 2002
- 7.10: October 1 2002
- 7.9.8: June 13 2002
- 7.9.7: May 10 2002
- 7.9.6: April 14 2002
- 7.9.5: March 7 2002
- 7.9.4: March 4 2002
- 7.9.3: January 23 2002
- 7.9.2: December 5 2001
- 7.9.1: November 4 2001
- 7.9: September 23 2001
- 7.8.1: August 20 2001
- 7.8: June 7 2001
- 7.7.3: May 4 2001
- 7.7.2: April 22 2001
- 7.7.1: April 3 2001
- 7.7: March 22 2001
- 7.6.1: February 9 2001
- 7.6: January 26 2001
- 7.5.2: January 4 2001
- 7.5.1: December 11 2000
- 7.5: December 1 2000
- 7.4.2: November 15 2000
- 7.4.1: October 16 2000
- 7.4: October 16 2000
- 7.3: September 28 2000
- 7.2.1: August 31 2000
- 7.2: August 30 2000
- 7.1.1: August 21 2000
- 7.1: August 7 2000
- 6.5.2: March 21 2000
- 6.5.1: March 20 2000
- 6.5: March 13 2000
- 6.4: January 17 2000
- 6.3.1: November 23 1999
- 6.3: November 10 1999
- 6.2: October 21 1999
- 6.1: October 17 1999
- 6.0: September 13 1999
- 5.11: August 25 1999
- 5.10: August 13 1999
- 5.9.1: July 30 1999
- 5.9: May 22 1999
- 5.8: May 5 1999
- 5.7.1: April 23 1999
- 5.7: April 20 1999
- 5.5.1: January 27 1999
- 5.5: January 15 1999
- 5.4: January 7 1999
- 5.3: December 21 1998
- 5.2.1: December 14 1998
- 5.2: December 14 1998
- 5.0: December 1 1998
- 4.10: October 26 1998
- 4.9: October 7 1998
- 4.8.4: September 20 1998
- 4.8.3: September 7 1998
- 4.8.2: August 14 1998
- 4.8.1: August 7 1998
- 4.8: July 30 1998
- 4.7: July 20 1998
- 4.6: July 3 1998
- 4.5.1: June 12 1998
- 4.5: May 30 1998
- 4.4: May 13 1998
- 4.3: April 30 1998
- 4.2: April 15 1998
- 4.1: April 3 1998
- 4.0: March 20 1998
- 3.12: March 14 1998
- 3.11: February 9 1998
- 3.10: February 4 1998
- 3.9: February 4 1998
- 3.7: January 15 1998
- 3.6: January 1 1998
- 3.5: December 15 1997
- 3.2: December 1 1997
- 3.1: November 24 1997
- 3.0: November 1 1997
- 2.9: October 15 1997
- 2.8: October 1 1997
- 2.7: September 20 1997
- 2.6: September 10 1997
- 2.5: September 1 1997
- 2.4: August 27 1997
- 2.3: August 21 1997
- 2.2: August 14 1997
- 2.1: August 10 1997
- 2.0: August 1 1997
- 1.5: July 21 1997
- 1.4: July 15 1997
- 1.3: June 1 1997
- 1.2: May 1 1997
- 1.1: April 20 1997
- 1.0: April 8 1997
- 0.3: February 1 1997
- 0.2: December 17 1996
- 0.1: November 11 1996

## Rock-solid curl

The long-term support releases of curl, called [Rock-solid
curl](https://rock-solid.curl.dev/), are managed separately and are for paying
customers only. They are made as releases branches off previous standard curl
releases, and use version numbers that were never used by the freely available
version.

- Rock-solid curl 8.18.1: February 25, 2026
- Rock-solid curl 8.18.2: September 2, 2026
<!--
Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.

SPDX-License-Identifier: curl
-->

# curl vulnerability disclosure policy

This document describes how security vulnerabilities are handled in the curl
project.

There is no bug bounty and the curl project never offers rewards for reported
vulnerabilities.

## Publishing Information

All known and public curl or libcurl related vulnerabilities are listed on
[the curl website security page](https://curl.se/docs/security.html).

Security vulnerabilities **should not** be entered in the project's public bug
tracker.

## Vulnerability Handling

The typical process for handling a new security vulnerability is as follows.

No information should be made public about a vulnerability until it is
formally announced at the end of this process. That means, for example, that a
bug tracker entry must NOT be created to track the issue since that makes the
issue public and it should not be discussed on any of the project's public
mailing lists. Messages associated with any commits should not make any
reference to the security nature of the commit if done prior to the public
announcement.

- The person discovering the issue, the reporter, reports the vulnerability on
  [HackerOne](https://hackerone.com/curl). Issues filed there reach a handful
  of selected and trusted people.

- When communicating in the curl project, please explain your issues or
  improvements briefly and clearly in your own human voice. Do not lazily
  paste massive, AI-generated explanations; as a contributor doing this
  infrequently, it is your responsibility to invest a few extra minutes into
  making your message digestible. The maintainers review submissions
  constantly, and clear writing reduces their daily burden and friction.

- The curl project cannot handle vulnerability reports sent to us over email.
  We lose track of the reports. We cannot easily disclose them. Please do not
  send us reports over email.

- Messages that do not relate to the reporting or managing of an undisclosed
  security vulnerability in curl or libcurl are ignored and no further action
  is required.

- A person in the security team responds to the original report to acknowledge
  that a human has seen the report.

- The security team investigates the report and either rejects it or accepts
  it. See below for examples of problems that are not considered
  vulnerabilities.

- If the report is rejected, the team writes to the reporter to explain why.

- If the report is accepted, the team writes to the reporter to let them
  know it is accepted and that they are working on a fix.

- The security team discusses the problem, works out a fix, considers the
  impact of the problem and suggests a release schedule. This discussion
  should involve the reporter as much as possible.

- The release of the information should be "as soon as possible" and is most
  often synchronized with an upcoming release that contains the fix. If the
  reporter, or anyone else involved, thinks the next planned release is too
  far away, then a separate earlier release should be considered.

- Write a security advisory draft about the problem that explains what the
  problem is, its impact, which versions it affects, solutions or workarounds,
  when the release is out and make sure to credit all contributors properly.
  Figure out the CWE (Common Weakness Enumeration) number for the flaw. See
  [SECURITY-ADVISORY](https://curl.se/dev/advisory.html) for help on creating
  the advisory.

- Request a CVE Id for the issue. curl is a CNA (CVE Numbering Authority) and
  can request its own numbers.

- Update the "security advisory" with the CVE number.

- The security team commits the fix in a private branch. The commit message
  should ideally contain the CVE number. If the severity level of the issue is
  set to Low or Medium, the fix is allowed to get merged into the master
  repository via a normal PR - but without mentioning it being a security
  vulnerability.

- No more than seven days before release, inform
  [distros@openwall](https://oss-security.openwall.org/wiki/mailing-lists/distros)
  to prepare them about the upcoming public security vulnerability
  announcement - attach the advisory draft for information with CVE and
  current patch. 'distros' does not accept an embargo longer than 7 days and
  they do not care for Windows-specific flaws.

- No more than 48 hours before the release, the private branch is merged into
  the master branch and pushed. Once pushed, the information is accessible to
  the public and the actual release should follow suit immediately afterwards.
  The time between the push and the release is used for final tests and
  reviews.

- The project team creates a release that includes the fix.

- The project team announces the release and the vulnerability to the world in
  the same manner we always announce releases. It gets sent to the
  curl-announce, curl-library and curl-users mailing lists.

- The security webpage on the website should get the new vulnerability
  mentioned.

## security (at curl dot se)

This is a private mailing list for discussions on and about curl security
issues.

Who is on this list? There are a couple of criteria you must meet, and then we
might ask you to join the list or you can ask to join it. It really is not a
formal process. We only require that you have a long-term presence in the curl
project and you have shown an understanding for the project and its way of
working. You must have been around for a good while and you should have no
plans of vanishing in the near future.

We do not make the list of participants public mostly because it tends to vary
somewhat over time and a list somewhere only risks getting outdated.

## Publishing Security Advisories

1. Write up the security advisory, using markdown syntax. Use the same
   subtitles as last time to maintain consistency.

2. Name the advisory file after the allocated CVE id.

3. Add a line on the top of the array in `curl-www/docs/vuln.pm`.

4. Put the new advisory markdown file in the `curl-www/docs/` directory. Add it
   to the git repository.

5. Run `make` in your local web checkout and verify that things look fine.

6. On security advisory release day, push the changes on the curl-www
   repository's remote master branch.

## Disclose the report

Request the issue to be disclosed. If there are sensitive details present in
the report and discussion, those should be redacted from the disclosure. The
default policy is to disclose as much as possible as soon as the vulnerability
has been published.

*All* reports submitted to the project, valid or not, should be disclosed and
made public.

# Severity levels

The curl project's security team rates security problems using four severity
levels depending on how serious we consider the problem to be. We use **Low**,
**Medium**, **High** and **Critical**. We refrain from using numerical scoring
of vulnerabilities.

We do not support CVSS as a method to grade security vulnerabilities, so we do
not set them for CVE records published by the curl project. We believe CVSS is
a broken system that often does not properly evaluate to suitable severity
levels that reflect all dimensions and factors involved. Other organizations
however set and provide CVSS scores for curl vulnerabilities. You need to
decide for yourself if you believe they know enough about the subjects
involved to make reasonable assessments. Deciding between four different
severity levels is hard enough for us.

When deciding severity level on a particular issue, we take all the factors
into account: attack vector, attack complexity, required privileges, necessary
build configuration, protocols involved, platform specifics and also what
effects a possible exploit or trigger of the issue can lead to, including
confidentiality, integrity or availability problems.

## Low

This is a security problem that is truly hard or unlikely to exploit or
trigger. Due to timing, platform requirements or the fact that options or
protocols involved are rare etc. [Past
example](https://curl.se/docs/CVE-2022-43552.html)

Issues that are likely to be detected by basic testing are likely to not be
considered more severe than **Low**. Users that do not test cannot be expected
to have secure setups to begin with.

## Medium

This is a security problem that is less hard than **Low** to exploit or
trigger. Less strict timing, wider platform availability or involving more
widely used options or protocols. A problem that usually needs something else
to also happen to become serious. [Past
example](https://curl.se/docs/CVE-2022-32206.html)

## High

This issue is in itself a serious problem with real world impact. Flaws that
can easily compromise the confidentiality, integrity or availability of
resources. Exploiting or triggering this problem is not hard. [Past
example](https://curl.se/docs/CVE-2019-3822.html)

## Critical

Easily exploitable by a remote unauthenticated attacker and lead to system
compromise (arbitrary code execution) without requiring user interaction, with
a common configuration on a popular platform. This issue has few restrictions
and requirements and can be exploited easily using most curl configurations.
[Past example](https://curl.se/docs/CVE-2000-0973.html)

# Not security issues

This is an incomplete list of issues that are not considered vulnerabilities.

## Small memory leaks

We do not consider a small memory leak a security problem; even if the amount
of allocated memory grows by a small amount every now and then. Long-living
applications and services already need to have countermeasures and deal with
growing memory usage, be it leaks or increased use. A small memory or resource
leak is then expected to *not* cause a security problem.

Of course there can be a discussion if a leak is small or not. A large leak
can be considered a security problem due to the DOS risk. If leaked memory
contains sensitive data it might also qualify as a security problem.

## Never-ending transfers

We do not consider flaws that cause a transfer to never end to be a security
problem. There are already several benign and likely reasons for transfers to
stall and never end, so applications that cannot deal with never-ending
transfers already need to have counter-measures established.

Well-known attacks, like
[Slowloris](https://en.wikipedia.org/wiki/Slowloris_(cyber_attack)), that send
partial requests are usually not considered a flaw. If the problem bypasses
the regular counter-measures and it causes a never-ending transfer, it might
be a security problem.

## Not practically possible

If the flaw or vulnerability cannot practically get executed on existing
hardware it is not a security problem.

## API misuse

If a reported issue only triggers by an application using the API in a way
that is not documented to work or even documented to not work, it is probably
not going to be considered a security problem. We only guarantee secure and
proper functionality when the APIs are used as expected and documented.

There can be a discussion about what the documentation actually means and how
to interpret the text, which might end up with us still agreeing that it is a
security problem.

## Local attackers already present

When an issue can only be attacked or misused by an attacker present on the
local system or network, the bar is raised. If a local user wrongfully has
elevated rights on your system enough to attack curl, they can probably
already do much worse harm and the problem is not really in curl.

## Debug & Experiments

Vulnerabilities in features which are off by default (in the build) and
documented as experimental, or exist only in debug mode, are not considered
security problems.

The same applies to scripts and software which are not installed by default
through the make install rule.

## Test code

curl has an extensive test suite with lots of code written specifically to
exercise and verify curl, libcurl and specific internal functions. The test
code and its associated test servers are *not* intended for production use.
They are not secure, you should not assume otherwise and must not report about
security problems in those.

## URL inconsistencies

URL parser inconsistencies between browsers and curl are expected and are not
considered security vulnerabilities. The WHATWG URL Specification and RFC
3986+ (the plus meaning that it is an extended version) [are not completely
interoperable](https://github.com/bagder/docs/blob/master/URL-interop.md).

Obvious parser bugs can still be vulnerabilities of course.

## Visible command line arguments

The curl command blanks the contents of a number of command line arguments to
prevent them from appearing in process listings. It does not blank all
arguments, even though some that are not blanked might contain sensitive
data. We consider this functionality a best-effort and omissions are not
security vulnerabilities.

- not all systems allow the arguments to be blanked in the first place
- since curl blanks the argument itself they are readable for a short moment
  no matter what
- virtually every argument can contain sensitive data, depending on use
- blanking all arguments would make it impractical for users to differentiate
  curl command lines in process listings

## Busy-loops

Busy-loops that consume 100% CPU time but eventually end (perhaps due to a set
timeout value or otherwise) are not considered security problems. Applications
are supposed to already handle situations when the transfer loop legitimately
consumes 100% CPU time, so while a prolonged such busy-loop is a nasty bug, we
do not consider it a security problem.

## Saving files

curl cannot protect against attacks where an attacker has write access to the
same directory where curl is directed to save files.

## Tricking a user to run a command line

A creative, misleading or funny looking command line is not a security
problem. The curl command line tool takes options and URLs on the command line
and if an attacker can trick the user to run a specifically crafted curl
command line, all bets are off. Such an attacker can already have the user run
a much worse command that can do something fatal (like `sudo rm -rf /`).

## Terminal output and escape sequences

Content that is transferred from a server and gets displayed in a terminal by
curl may contain escape sequences or use other tricks to fool the user. This
is curl working as designed and is not a curl security problem. Escape
sequences, moving cursor, changing color etc, is also frequently used for
good. To reduce the risk of getting fooled, save files and browse them after
download using a display method that minimizes risks.

## NULL dereferences and crashes

If a malicious server can trigger a NULL dereference in curl or otherwise
cause curl to crash (and nothing worse), chances are big that we do not
consider that a security problem.

Malicious servers can already cause considerable harm and denial of service
like scenarios without having to trigger such code paths. For example by
stalling, being terribly slow or by delivering enormous amounts of data.
Additionally, applications are expected to handle "normal" crashes without
that being the end of the world.

There need to be more and special circumstances to treat such problems as
security issues.

## Legacy dependencies

Problems that can be triggered only by the use of a *legacy dependency* are
not considered security problems.

A *legacy dependency* is here defined as:

- the legacy version was released over ten years ago AND

- the legacy version is no longer in use by any existing still supported
  operating system or distribution AND

- there are modern versions of equivalent or better functionality offered and
  in common use

## Weak algorithms required for functionality

curl supports several algorithms that are considered weak, like DES and MD5.
These algorithms are still not curl security vulnerabilities or security
problems as they are only used when the users explicitly ask for their use by
using the protocols or options that require the use of those algorithms.

When servers upgrade to use secure alternatives, curl users should use those
options/protocols.

## CRLF in data

curl makes barely any claims of *cleaning* input or rejecting invalid data. A
user that uses a curl feature can send in *creative* sequences that include
carriage-return (CR) or line-feed (LF) characters.

Therefore, we reject the idea of *CRLF injection* as a security problem. It is
a *feature* that users can send creative byte sequences. If users do not want
to send such octets, they are in control and should avoid sending such bytes
to curl.

For example, a user might pass in a username that looks like
`Mr[CR][LF]Smith`. It may cause some minor havoc in the protocol handling,
depending on what protocol is used.

## Non-released code

Only curl releases are ever considered *secure*. Between releases, we are
under development and then we may have code present in the git repository that
is insecure, but without those flaws being considered as vulnerabilities.
Another reason we strongly suggest you only use curl release versions in
production.

Unreleased code may also contain fixes to problems that were present in the
most recent release.

# curl major incident response

Vulnerability disclosure manages the full life cycle of a vulnerability
affecting curl - where the **curl-security** team privately engages with
reporters coordinating on embargo and eventual release of security fixes.

For most vulnerabilities (even critical vulnerabilities) this is the
normal _'mode'_ of incident response.

A **major incident** is defined as something that has much larger scope and
impact on users and developers of curl.

A major incident usually encompasses one or more of the following:
* broad and deep impact on developers, distros and users
* high visibility
* remote code execution
* exploit readily available
* critical curl infrastructure compromised
* time sensitive
* premature disclosure (e.g. embargo broken)

A major incident is declared only when it is deemed that the normal
vulnerability disclosure process is not sufficient.

The curl **major incident** process is as follows:

## Major incident begins

Only a member of the **curl-security** team can declare a **major incident**
via any or all of the following communication channels:

* **irc**: channel #curl on the network [Libera.Chat](https://libera.chat/)
* **mailing-lists**:
  * curl-announce
  * curl-users
  * curl-distros
* **website**: [curl.se](https://curl.se/)

This declaration may also be transmitted via other channels, though the
above are considered official channels.

The veracity of such a communication can be verified by consulting two
or more **curl-security** team members.

This announcement nominates, from **curl-security** team, the following
roles:

* **incident lead** - Coordinates technical efforts
* **communication lead** - Single point of public contact

It is likely that our
[BDFL](https://en.wikipedia.org/wiki/Benevolent_dictator_for_life) occupies
one of these roles, though this plan does not depend on it.

A declaration may also contain more detailed information but as we honor
embargoes and vulnerability disclosure throughout this process, it may also
contain a brief notification that a **major incident** is occurring.

## Major incident ongoing

During the incident - all press, media, legal or commercial entities should
contact communication lead (security@curl.se).

Existing **curl-security** team internal communication channels are used
for all internal communication.

Existing vulnerability disclosure process are followed for any embargoes
and fixes.

Where possible, public communications are provided:
* regular communication from communication lead (for example daily update)
* asynchronous communication from incident lead

* Delivered to the aforementioned curl communication channels.

A log is kept of all external and internal communication.

Once fixes have been released we may provide a more detailed postmortem and
overall timeline of events.

## Major incident ends

Both the incident and communication leads declare when a **major incident**
has finished.

Any notices are removed and a return to normal vulnerability disclosure
process.
---
c: Copyright (C) Samuel Henrique <samueloph@debian.org>, Sergio Durigan Junior <sergiodj@debian.org> and many contributors, see the AUTHORS file.
SPDX-License-Identifier: curl
Title: wcurl
Section: 1
Source: wcurl
See-also:
  - curl (1)
  - trurl (1)
Added-in: n/a
---

# NAME

**wcurl** - a simple wrapper around curl to easily download files.

# SYNOPSIS

**wcurl \<URL\>...**

**wcurl [--curl-options \<CURL_OPTIONS\>]... [--dry-run] [--no-decode-filename] [-o|-O|--output \<PATH\>] [--] \<URL\>...**

**wcurl [--curl-options=\<CURL_OPTIONS\>]... [--dry-run] [--no-decode-filename] [--output=\<PATH\>] [--] \<URL\>...**

**wcurl -V|--version**

**wcurl -h|--help**

# DESCRIPTION

**wcurl** is a simple curl wrapper which lets you use curl to download files
without having to remember any parameters.

Call **wcurl** with a list of URLs you want to download and **wcurl**
picks sane defaults.

If you need anything more complex, you can provide any of curl's supported
parameters via the **--curl-options** option. Beware that you likely should
be using curl directly if your use case is not covered.

By default, **wcurl** does:

## * Percent-encode whitespace in URLs;

## * Download multiple URLs in parallel
    if the installed curl's version is \>= 7.66.0 (--parallel);

## * Use a total number of 5 parallel connections to the same protocol + hostname + port number target
    if the installed curl's version is \>= 8.16.0 (--parallel-max-host);

## * Follow redirects;

## * Automatically choose a filename as output;

## * Avoid overwriting files
    if the installed curl's version is \>= 7.83.0 (--no-clobber);

## * Perform retries;

## * Set the downloaded file timestamp
    to the value provided by the server, if available;

## * Default to https
    if the URL does not contain any scheme;

## * Disable curl's URL globbing parser
    so {} and [] characters in URLs are not treated specially;

## * Percent-decode the resulting filename;

## * Use 'index.html' as the default filename
    if there is none in the URL.

# OPTIONS

## --curl-options, --curl-options=\<CURL_OPTIONS\>...

Specify extra options to be passed when invoking curl. May be specified more
than once.

## -o, -O, --output, --output=\<PATH\>

Use the provided output path instead of getting it from the URL. If multiple
URLs are provided, resulting files share the same name with a number appended to
the end (curl \>= 7.83.0). If this option is provided multiple times, only the
last value is considered.

## --no-decode-filename

Do not percent-decode the output filename, even if the percent-encoding in the
URL was done by **wcurl**, e.g.: The URL contained whitespace.

## --dry-run

Do not actually execute curl, print what would be invoked.

## -V, \--version

Print version information.

## -h, \--help

Print help message.

# CURL_OPTIONS

Any option supported by curl can be set here. This is not used by **wcurl**; it
is instead forwarded to the curl invocation.

# URL

URL to be downloaded. Anything that is not a parameter is considered
an URL. Whitespace is percent-encoded and the URL is passed to curl, which
then performs the parsing. May be specified more than once.

# EXAMPLES

Download a single file:

**wcurl example.com/filename.txt**

Download two files in parallel:

**wcurl example.com/filename1.txt example.com/filename2.txt**

Download a file passing the **--progress-bar** and **--http2** flags to curl:

**wcurl --curl-options="--progress-bar --http2" example.com/filename.txt**

Resume from an interrupted download. The options necessary to resume the download
(`--clobber --continue-at -`) must be the **last** options specified in `--curl-options`.
Note that the only way to resume interrupted downloads is to allow wcurl to overwrite
the destination file:

**wcurl --curl-options="--clobber --continue-at -" example.com/filename.txt**

Download multiple files without a limit of concurrent connections per host (the default limit is 5):

**wcurl --curl-options="--parallel-max-host 0" example.com/filename1.txt example.com/filename2.txt**

# AUTHORS

    Samuel Henrique \<samueloph@debian.org\>
    Sergio Durigan Junior \<sergiodj@debian.org\>
    and many contributors, see the AUTHORS file.

# REPORTING BUGS

If you experience any problems with **wcurl** that you do not experience with
curl, submit an issue on GitHub: https://github.com/curl/wcurl

# COPYRIGHT

**wcurl** is licensed under the curl license
