Files
azerothcore-wotlk-pbot/deps/curl/docs/HTTP3.md
kadeshar 236c842934 Core merge 17112025 (#104)
* fix(DB/SmartAI): improve Harry surrendering during quest 'Gambling Debt' (#23598)

* fix(DB/Quest): The Kalu'ak dailies reward 500 rep (#23600)

* chore(DB): import pending files

Referenced commit(s): fb03f41b2a

* fix(DB/GameEvent): Remove midsummer pole in K3 (#23614)

* chore(DB): import pending files

Referenced commit(s): 7b0000d6ee

* fix(DB/SmartAI): increase reliability of quest event Foolish Endeavors (#23612)

* chore(DB): import pending files

Referenced commit(s): 86f219abbc

* fix(Scripts/AreaTrigger): players become stuck after Last Rites (#23613)

* chore(DB): import pending files

Referenced commit(s): c1a8047cf1

* fix(Core/Vmaps): Fix inconsistency of hitInstance and hitModel to cause wrong area ids (#23233)

Co-authored-by: ModoX <moardox@gmail.com>
Co-authored-by: Shauren <shauren.trinity@gmail.com>
Co-authored-by: Grimdhex <237474256+Grimdhex@users.noreply.github.com>
Co-authored-by: sudlud <sudlud@users.noreply.github.com>

* fix(DB/Gameobject): Sniffed Values for 'Wild Mustard' spawns (#23608)

* fix(DB/SmartAI): remove large combat distance of Frostbrood Sentry (#23607)

* chore(DB): import pending files

Referenced commit(s): 41d40b236f

* fix(DB/ReputationRewardRate): Patch 3.0.0 gain for Northrend factions (#23597)

* chore(DB): import pending files

Referenced commit(s): 067a898caa

* fix(Core/Map): It should be ensured that the instance is unloaded only after the Creature Respawn. (#23103)

* fix(Scripts/Northrend): Sniffing Out The Perpetrator horde (#23620)

* fix(Scripts/Northrend): ensure Drakuru stays in place during Betrayal (#23619)

* chore(DB): import pending files

Referenced commit(s): 928e145694

* fix(DB/SmartAI): quest 'Reconnaissance Flight' (#23628)

Co-authored-by: dr-j <dr-j@users.noreply.github.com>
Co-authored-by: Killyana <morphone1@gmail.com>

* fix(DB/QuestOfferReward): remove mention of a beta recipe in text (#23629)

* fix(DB/Conditions): update quest conditions to drop chokers (#23610)

* chore(DB): import pending files

Referenced commit(s): bca8f7ce07

* refactor(Core/PlayerScript): Delete OnPlayerChat, use OnPlayerCanUseChat (#23617)

* fix(Core/SmartAI): startup warnings unused params (#23551)

* fix(Core/Unit): Druid Talent Survival of the Fittest lacking immunity to creature daze (#23471)

* fix(DB/SAI): Fix Fizzcrank Paradrop teleporters (#23633)

* chore(DB): import pending files

Referenced commit(s): 94ba1c210d

* fix(Core): Fix waterwalking after dying in instance (#23593)

* fix(DB/SAI): don't remove all auras when mounting flamebringer (#23640)

* chore(DB): import pending files

Referenced commit(s): 22f91f3802

* fix(DB/SAI): Emerald Lasher goes out of the terrain when aggroed. (#23642)

* chore(DB): import pending files

Referenced commit(s): f9d6fe41de

* fix(DB/SAI): Burning Depths Necromancer no longer stays in place. (#23641)

* chore(DB): import pending files

Referenced commit(s): 1037471c8d

* fix(DB/SAI): Remove SmartAI from Valkyrion Harpoon Gun. (#23646)

* chore(DB): import pending files

Referenced commit(s): 8e3a7e6dcf

* fix(DB/Creature): Fix Weakened Reanimated Frost Wyrm inhabit type (#23645)

* chore(DB): import pending files

Referenced commit(s): 3baa18ef5b

* fix(DB/Spell): Infectious Bites should stack from different casters (#23647)

* chore(DB): import pending files

Referenced commit(s): 5aede412ab

* fix(DB/SAI): Solve various issues with It Goes to 11... quest. (#23651)

* fix(DB/Loot): Fireproof Satchel will now always drop the Ritual of Torch  (#23585)

* chore(DB): import pending files

Referenced commit(s): 1090c209b3

* fix(Scripts/Northrend): Betrayal quest (#23650)

* fix(Script/BlackTemple): Reliquary of Souls will use 45 degree in front to set incombat (#22938)

* fix(Scripts/Spell): Fix Animal Blood spawning when it shouldn't (#23656)

* fix(Scripts/BoreanTundra): Script Bloodspore Haze/Psychosis (#23657)

* chore(DB): import pending files

Referenced commit(s): baf7957e36

* fix(DB/SAI): Sibling Rivalry quest credit if mounted (#23659)

* chore(DB): import pending files

Referenced commit(s): 6919cc679d

* fix(docs/license): use GPLv2 as MaNGOS-based project (#23655)

* fix(Core/Achievements): a character can only have 1 race realm first (#23626)

* chore: fix leftover license header (#23678)

* fix(Scripts/HoL): Update Loken script (#23587)

* fix(Scripts/DTK): Update King Dred script (#23572)

* fix(DB/SAI): Bitter Departure quest credit (#23658)

* chore(DB): import pending files

Referenced commit(s): e595425578

* fix(DB/Conditions): Ice Shard require Icy Imprisonment (#23661)

* chore(DB): import pending files

Referenced commit(s): 8294652e77

* fix(DB/Loot): add Scourge Curio drop to Lost Shandaral Spirit (#23686)

* chore(DB): import pending files

Referenced commit(s): b6ed4347fe

* fix(DB/Gameobject): fix spell focus location for 'Will of the Titans' (#23683)

* chore(DB): import pending files

Referenced commit(s): 388f18895d

* fix(DB/Creature): update IOC Demolisher spells (#23685)

* chore(DB): import pending files

Referenced commit(s): cdfa50c990

* fix(Scripts/Northrend): IOC boss cast ability Mortal Strike (#23684)

* fix(Scripts/BoreanTundra): Fix Beryl Sorcerer engaging mobs (#23690)

* fix(Core/Entities): Improve interactions between taxis and players regarding PvP flag. (#23681)

* fix(DB/Creature): Peon Gakra should be an innkeeper (#23699)

* chore(DB): import pending files

Referenced commit(s): 6abff4ac2b

* fix(Scripts/SholazarBasin): Fix Song of Wind and Water double credit (#23707)

* fix(DB/SAI): Reanimated Frost Wyrm engage after being hit by quest spell (#23697)

* fix(DB/SAI): Timely respawn Nesingwary Trappers (#23703)

* fix(DB/Creature): Fix Fjord Hawk Matriarch unit flags (#23696)

* fix(DB/Conditions): Fix Fordragon Resolve target conditions (#23701)

* chore(DB): import pending files

Referenced commit(s): 2942d63125

* fix(DB/Script): Move Tailhorn Stag and Amberpine Woodsman behavior into SmartAI. (#23708)

* fix(DB/Creature): Set Trigger flag on Steam Vent. (#23710)

* chore(DB): import pending files

Referenced commit(s): 435ca302ef

* fix(DB/SAI): To Stars' Rest! taxi flight (#23712)

* chore(DB): import pending files

Referenced commit(s): ab4d59ac9d

* fix (DB/Creature): Set Surveyor Orlond flags. (#23714)

* chore(DB): import pending files

Referenced commit(s): e8ec77dca7

* fix(DB/Loot): Fix Master Summoner Staff drop chance (#23717)

* chore(DB): import pending files

Referenced commit(s): 182c055e6e

* fix(Scripts/DTK): Fix Oh Novos! achievement (#23539) (#23718)

* fix(Core/Spells): Remove King Mrgl-Mrgl costume on spell casting (#23713)

* chore(DB): import pending files

Referenced commit(s): 8c963a11ce

* fix(DB/Reputation): Utigarde Pinnacle normal reputation (#23719)

* chore(DB): import pending files

Referenced commit(s): 88ed7d66d5

* fix(Scripts/HoS): Clean up faction update hacks (#23720)

* fix(DB/Reputation): Lower reputation according to rates handling (#23722)

* fix(DB/Reputation): Oculus normal & UP correction (#23723)

* chore(DB): import pending files

Referenced commit(s): abc2cf3028

* fix(Scripts/Oculus): Implement crossfaction support for drakes (#23704)

* fix(DB/Quest): Correct prerequisite for Reclaimed Ration (#23736)

Co-authored-by: blinkysc <blinkysc@users.noreply.github.com>

* fix(DB/Quest): Correct prerequisite for Salvaging Life's Strength (#23734)

Co-authored-by: blinkysc <blinkysc@users.noreply.github.com>

* chore(DB): import pending files

Referenced commit(s): afd8197588

* fix(Core/Movement): Fix SummonMovementInform for summons (#23725)

* refactor(Core/Movement): Fix Build (#23739)

* fix(DB/SAI): Update Iron Rune Construct SAI to use DO_ACTION instead … (#23716)

* chore(DB): import pending files

Referenced commit(s): 7cc39f78e2

* fix(DB/SAI): Fix Flamebringer gossip interaction (#23740)

* chore(DB): import pending files

Referenced commit(s): 9cb683cfcd

* fix(DB/SAI): Nerub'ar member packs now attack together. (#23727)

* chore(DB): import pending files

Referenced commit(s): 6f5a1b7ccc

* fix(DB/SAI): Remove Harrison Johnes quest flag on escort accept (#23700)

* chore(DB): import pending files

Referenced commit(s): bacf15d356

* Update crash issue template with log submission guidelines (#23754)

* Merge

* Updated OnPlayerChat method name to OnPlayerCanUseChat

---------

Co-authored-by: sogladev <sogladev@gmail.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: 天鹭 <18535853+PkllonG@users.noreply.github.com>
Co-authored-by: ModoX <moardox@gmail.com>
Co-authored-by: Shauren <shauren.trinity@gmail.com>
Co-authored-by: Grimdhex <237474256+Grimdhex@users.noreply.github.com>
Co-authored-by: sudlud <sudlud@users.noreply.github.com>
Co-authored-by: dr-j <dr-j@users.noreply.github.com>
Co-authored-by: Killyana <morphone1@gmail.com>
Co-authored-by: Undo <50205200+UndoUreche@users.noreply.github.com>
Co-authored-by: Andrew <47818697+Nyeriah@users.noreply.github.com>
Co-authored-by: killerwife <killerwife@gmail.com>
Co-authored-by: Tereneckla <Tereneckla@pm.me>
Co-authored-by: Rocco Silipo <108557877+Rorschach91@users.noreply.github.com>
Co-authored-by: Ryan Turner <16946913+TheSCREWEDSoftware@users.noreply.github.com>
Co-authored-by: blinkysc <37940565+blinkysc@users.noreply.github.com>
Co-authored-by: Francesco Borzì <borzifrancesco@gmail.com>
Co-authored-by: Benjamin Jackson <38561765+heyitsbench@users.noreply.github.com>
Co-authored-by: Traesh <Traesh@users.noreply.github.com>
Co-authored-by: blinkysc <blinkysc@users.noreply.github.com>
2025-11-23 20:45:22 +01:00

14 KiB

HTTP3 (and QUIC)

Resources

HTTP/3 Explained - the online free book describing the protocols involved.

quicwg.org - home of the official protocol drafts

QUIC libraries

QUIC libraries we are using:

ngtcp2

quiche - EXPERIMENTAL

OpenSSL 3.2+ QUIC - EXPERIMENTAL

msh3 (with msquic) - EXPERIMENTAL

Experimental

HTTP/3 support in curl is considered EXPERIMENTAL until further notice when built to use quiche or msh3. 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, just 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.

  • ngtcp2: v1.2.0
  • nghttp3: v1.1.0

Build with quictls

OpenSSL does not offer the required APIs for building a QUIC client. You need to use a TLS library that has such APIs and that works with ngtcp2.

Build quictls:

 % git clone --depth 1 -b openssl-3.1.4+quic https://github.com/quictls/openssl
 % cd openssl
 % ./config enable-tls1_3 --prefix=<somewhere1>
 % make
 % make install

Build nghttp3:

 % cd ..
 % git clone -b v1.1.0 https://github.com/ngtcp2/nghttp3
 % cd nghttp3
 % git submodule update --init
 % autoreconf -fi
 % ./configure --prefix=<somewhere2> --enable-lib-only
 % make
 % make install

Build ngtcp2:

 % cd ..
 % git clone -b v1.2.0 https://github.com/ngtcp2/ngtcp2
 % cd ngtcp2
 % autoreconf -fi
 % ./configure PKG_CONFIG_PATH=<somewhere1>/lib/pkgconfig:<somewhere2>/lib/pkgconfig LDFLAGS="-Wl,-rpath,<somewhere1>/lib" --prefix=<somewhere3> --enable-lib-only
 % make
 % make install

Build curl:

 % cd ..
 % git clone https://github.com/curl/curl
 % cd curl
 % autoreconf -fi
 % LDFLAGS="-Wl,-rpath,<somewhere1>/lib" ./configure --with-openssl=<somewhere1> --with-nghttp3=<somewhere2> --with-ngtcp2=<somewhere3>
 % make
 % make install

For OpenSSL 3.0.0 or later builds on Linux for x86_64 architecture, substitute all occurrences of "/lib" with "/lib64"

Build with GnuTLS

Build GnuTLS:

 % git clone --depth 1 https://gitlab.com/gnutls/gnutls.git
 % cd gnutls
 % ./bootstrap
 % ./configure --prefix=<somewhere1>
 % make
 % make install

Build nghttp3:

 % cd ..
 % git clone -b v1.1.0 https://github.com/ngtcp2/nghttp3
 % cd nghttp3
 % git submodule update --init
 % autoreconf -fi
 % ./configure --prefix=<somewhere2> --enable-lib-only
 % make
 % make install

Build ngtcp2:

 % cd ..
 % git clone -b v1.2.0 https://github.com/ngtcp2/ngtcp2
 % cd ngtcp2
 % autoreconf -fi
 % ./configure PKG_CONFIG_PATH=<somewhere1>/lib/pkgconfig:<somewhere2>/lib/pkgconfig LDFLAGS="-Wl,-rpath,<somewhere1>/lib" --prefix=<somewhere3> --enable-lib-only --with-gnutls
 % make
 % make install

Build curl:

 % cd ..
 % git clone https://github.com/curl/curl
 % cd curl
 % autoreconf -fi
 % ./configure --with-gnutls=<somewhere1> --with-nghttp3=<somewhere2> --with-ngtcp2=<somewhere3>
 % make
 % make install

Build with wolfSSL

Build wolfSSL:

 % git clone https://github.com/wolfSSL/wolfssl.git
 % cd wolfssl
 % autoreconf -fi
 % ./configure --prefix=<somewhere1> --enable-quic --enable-session-ticket --enable-earlydata --enable-psk --enable-harden --enable-altcertchains
 % make
 % make install

Build nghttp3:

 % cd ..
 % git clone -b v1.1.0 https://github.com/ngtcp2/nghttp3
 % cd nghttp3
 % git submodule update --init
 % autoreconf -fi
 % ./configure --prefix=<somewhere2> --enable-lib-only
 % make
 % make install

Build ngtcp2:

 % cd ..
 % git clone -b v1.2.0 https://github.com/ngtcp2/ngtcp2
 % cd ngtcp2
 % autoreconf -fi
 % ./configure PKG_CONFIG_PATH=<somewhere1>/lib/pkgconfig:<somewhere2>/lib/pkgconfig LDFLAGS="-Wl,-rpath,<somewhere1>/lib" --prefix=<somewhere3> --enable-lib-only --with-wolfssl
 % make
 % make install

Build curl:

 % cd ..
 % git clone https://github.com/curl/curl
 % cd curl
 % autoreconf -fi
 % ./configure --with-wolfssl=<somewhere1> --with-nghttp3=<somewhere2> --with-ngtcp2=<somewhere3>
 % make
 % make install

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:

 % git clone --recursive -b 0.22.0 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 quiche/deps/boringssl/src/lib
 % ln -vnf $(find target/release -name libcrypto.a -o -name libssl.a) quiche/deps/boringssl/src/lib/

Build curl:

 % cd ..
 % git clone https://github.com/curl/curl
 % cd curl
 % autoreconf -fi
 % ./configure LDFLAGS="-Wl,-rpath,$PWD/../quiche/target/release" --with-openssl=$PWD/../quiche/quiche/deps/boringssl/src --with-quiche=$PWD/../quiche/target/release
 % make
 % make install

If make install results in Permission denied error, you need to prepend it with sudo.

OpenSSL version

QUIC support is EXPERIMENTAL

Build OpenSSL 3.3.1:

 % cd ..
 % git clone -b openssl-3.3.1 https://github.com/openssl/openssl
 % cd openssl
 % ./config enable-tls1_3 --prefix=<somewhere> --libdir=lib
 % make
 % make install

Build nghttp3:

 % cd ..
 % git clone -b v1.1.0 https://github.com/ngtcp2/nghttp3
 % cd nghttp3
 % git submodule update --init
 % autoreconf -fi
 % ./configure --prefix=<somewhere2> --enable-lib-only
 % make
 % make install

Build curl:

 % cd ..
 % git clone https://github.com/curl/curl
 % cd curl
 % autoreconf -fi
 % LDFLAGS="-Wl,-rpath,<somewhere>/lib" ./configure --with-openssl=<somewhere> --with-openssl-quic --with-nghttp3=<somewhere2>
 % make
 % make install

You can build curl with cmake:

 % cd ..
 % git clone https://github.com/curl/curl
 % cd curl
 % cmake . -B bld -DCURL_USE_OPENSSL=ON -DUSE_OPENSSL_QUIC=ON
 % cmake --build bld
 % cmake --install bld

If make install results in Permission denied error, you need to prepend it with sudo.

msh3 (msquic) version

Note: The msquic HTTP/3 backend is immature and is not properly functional one as of September 2023. Feel free to help us test it and improve it, but there is no point in filing bugs about it just yet.

msh3 support is EXPERIMENTAL

Build Linux (with quictls fork of OpenSSL)

Build msh3:

 % git clone -b v0.6.0 --depth 1 --recursive https://github.com/nibanks/msh3
 % cd msh3 && mkdir build && cd build
 % cmake -G 'Unix Makefiles' -DCMAKE_BUILD_TYPE=RelWithDebInfo ..
 % cmake --build .
 % cmake --install .

Build curl:

 % git clone https://github.com/curl/curl
 % cd curl
 % autoreconf -fi
 % ./configure LDFLAGS="-Wl,-rpath,/usr/local/lib" --with-msh3=/usr/local --with-openssl
 % make
 % make install

Run from /usr/local/bin/curl.

Build Windows

Build msh3:

 % git clone -b v0.6.0 --depth 1 --recursive https://github.com/nibanks/msh3
 % cd msh3 && mkdir build && cd build
 % cmake -G 'Visual Studio 17 2022' -DCMAKE_BUILD_TYPE=RelWithDebInfo ..
 % cmake --build . --config Release
 % cmake --install . --config Release

Note - On Windows, Schannel is used for TLS support by default. If you with to use (the quictls fork of) OpenSSL, specify the -DQUIC_TLS=openssl option to the generate command above. Also note that OpenSSL brings with it an additional set of build dependencies not specified here.

Build curl (in Visual Studio Command prompt):

 % git clone https://github.com/curl/curl
 % cd curl/winbuild
 % nmake /f Makefile.vc mode=dll WITH_MSH3=dll MSH3_PATH="C:/Program Files/msh3" MACHINE=x64

Run in the C:/Program Files/msh3/lib directory, copy curl.exe to that directory, or copy msquic.dll and msh3.dll from that directory to the curl.exe directory. For example:

 % C:\Program Files\msh3\lib> F:\curl\builds\libcurl-vc-x64-release-dll-ipv6-sspi-schannel-msh3\bin\curl.exe --http3 https://curl.se/

--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 eyeballing

With option --http3 curl attempts earlier HTTP versions as well should the connect attempt via HTTP/3 not succeed "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.

So, 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 - just 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.

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 just 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 https://github.com/nghttp2/nghttp2.git
 % cd nghttp2
 % autoreconf -fi
 % PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/home/daniel/build-quictls/lib/pkgconfig:/home/daniel/build-nghttp3/lib/pkgconfig:/home/daniel/build-ngtcp2/lib/pkgconfig LDFLAGS=-L/home/daniel/build-quictls/lib CFLAGS=-I/home/daniel/build-quictls/include ./configure --enable-maintainer-mode --prefix=/home/daniel/build-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 just use the test cert that exists in curl's test dir.

 % CERT=$CURLSRC/tests/stunnel.pem
 % $HOME/bin/nghttpx $CERT $CERT --backend=localhost,80 \
  --frontend="localhost,9443;quic"

Caddy

Install Caddy. 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