Skip to content

Commit

Permalink
add support for http/3+quic
Browse files Browse the repository at this point in the history
New flag `--quic` to enable. Requires `--ssl-listen` as well.
  • Loading branch information
dropwhile committed Nov 8, 2023
1 parent d3b0ad9 commit 59a4227
Show file tree
Hide file tree
Showing 4 changed files with 109 additions and 25 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ toc::[]
:link-proxy-from-env: https://golang.org/pkg/net/http/#ProxyFromEnvironment

== HEAD
* Add http/3+quic server support. New flag `--quic`. Requires `--ssl-listen`.

== v2.4.6 - 2023-10-25
* Add `--no-debug-vars` flag to disable /debug/vars when `--metrics` is
Expand Down
87 changes: 66 additions & 21 deletions cmd/go-camo/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"github.com/cactus/go-camo/v2/pkg/camo"
"github.com/cactus/go-camo/v2/pkg/htrie"
"github.com/cactus/go-camo/v2/pkg/router"
"github.com/quic-go/quic-go/http3"

"github.com/cactus/mlog"
flags "github.com/jessevdk/go-flags"
Expand Down Expand Up @@ -155,6 +156,7 @@ func main() {
BindAddress string `long:"listen" default:"0.0.0.0:8080" description:"Address:Port to bind to for HTTP"`
BindAddressSSL string `long:"ssl-listen" description:"Address:Port to bind to for HTTPS/SSL/TLS"`
BindSocket string `long:"socket-listen" description:"Path for unix domain socket to bind to for HTTP"`
EnableQuic bool `long:"quic" description:"Enable http3/quic. Binds to the same port number as ssl-listen but udp+quic."`
SSLKey string `long:"ssl-key" description:"ssl private key (key.pem) path"`
SSLCert string `long:"ssl-cert" description:"ssl cert (cert.pem) path"`
MaxSize int64 `long:"max-size" description:"Max allowed response size (KB)"`
Expand Down Expand Up @@ -236,6 +238,9 @@ func main() {
if opts.BindAddressSSL != "" && opts.SSLCert == "" {
mlog.Fatal("ssl-cert is required when specifying ssl-listen")
}
if opts.EnableQuic && opts.BindAddressSSL == "" {
mlog.Fatal("ssl-listen is required when specifying quic")
}

// set keepalive options
config.DisableKeepAlivesBE = opts.DisableKeepAlivesBE
Expand Down Expand Up @@ -352,9 +357,36 @@ func main() {

mux.Handle("/", router)

srv := &http.Server{
ReadTimeout: 30 * time.Second,
Handler: mux,
var httpSrv *http.Server
var tlsSrv *http.Server
var quicSrv *http3.Server

if opts.BindAddress != "" {
httpSrv = &http.Server{
Addr: opts.BindAddress,
ReadTimeout: 30 * time.Second,
Handler: mux,
}
}

if opts.BindAddressSSL != "" {
tlsSrv = &http.Server{
Addr: opts.BindAddressSSL,
ReadTimeout: 30 * time.Second,
Handler: mux,
}

if opts.EnableQuic {
quicSrv = &http3.Server{
Addr: opts.BindAddressSSL,
Handler: mux,
}
// wrap default mux to set some default quic reference headers on tls responses
tlsSrv.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
quicSrv.SetQuicHeaders(w.Header())
mux.ServeHTTP(w, r)
})
}
}

idleConnsClosed := make(chan struct{})
Expand All @@ -364,14 +396,28 @@ func main() {
signal.Notify(sigint, os.Interrupt, syscall.SIGTERM)
s := <-sigint
mlog.Info("Handling signal:", s)

mlog.Info("Starting graceful shutdown")

d := time.Now().Add(200 * time.Millisecond)
closeWait := 200 * time.Millisecond
d := time.Now().Add(closeWait)
ctx, cancel := context.WithDeadline(context.Background(), d)

if err := srv.Shutdown(ctx); err != nil {
mlog.Info("Error gracefully shutting down server:", err)
if httpSrv != nil {
if err := httpSrv.Shutdown(ctx); err != nil {
mlog.Info("Error gracefully shutting down HTTP server:", err)
}
}

if tlsSrv != nil {
if err := tlsSrv.Shutdown(ctx); err != nil {
mlog.Info("Error gracefully shutting down HTTP/TLS server:", err)
}
}

if quicSrv != nil {
if err := quicSrv.CloseGracefully(closeWait); err != nil {
mlog.Info("Error gracefully shutting down HTTP3/QUIC server:", err)
}
}
// Even though ctx may be expired, it is good practice to call its
// cancellation function in any case. Failure to do so may keep the
Expand All @@ -393,35 +439,34 @@ func main() {
mlog.Fatal("Error listening on unix socket", err)
}

if err := srv.Serve(ln); err != http.ErrServerClosed {
if err := httpSrv.Serve(ln); err != http.ErrServerClosed {
mlog.Fatal(err)
}
}()
}

if opts.BindAddress != "" {
if httpSrv != nil {
mlog.Printf("Starting HTTP server on: tcp:%s", opts.BindAddress)
go func() {
ln, err := net.Listen("tcp", opts.BindAddress)
if err != nil {
mlog.Fatal("Error listening on tcp socket", err)
}

if err := srv.Serve(ln); err != http.ErrServerClosed {
if err := httpSrv.ListenAndServe(); err != http.ErrServerClosed {
mlog.Fatal(err)
}
}()
}

if opts.BindAddressSSL != "" {
mlog.Printf("Starting TLS server on: tcp:%s", opts.BindAddressSSL)
if tlsSrv != nil {
mlog.Printf("Starting HTTP/TLS server on: tcp:%s", opts.BindAddressSSL)
go func() {
ln, err := net.Listen("tcp", opts.BindAddressSSL)
if err != nil {
mlog.Fatal("Error listening on tcp socket", err)
if err := tlsSrv.ListenAndServeTLS(opts.SSLCert, opts.SSLKey); err != http.ErrServerClosed {
mlog.Fatal(err)
}
}()
}

if err := srv.ServeTLS(ln, opts.SSLCert, opts.SSLKey); err != http.ErrServerClosed {
if quicSrv != nil {
mlog.Printf("Starting HTTP3/QUIC server on: udp:%s", opts.BindAddressSSL)
go func() {
if err := quicSrv.ListenAndServeTLS(opts.SSLCert, opts.SSLKey); err != http.ErrServerClosed {
mlog.Fatal(err)
}
}()
Expand Down
13 changes: 12 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,31 @@ require (
github.com/jessevdk/go-flags v1.5.0
github.com/prometheus/client_golang v1.17.0
github.com/prometheus/common v0.45.0
github.com/quic-go/quic-go v0.40.0
github.com/xlab/treeprint v1.2.0
golang.org/x/net v0.17.0
golang.org/x/net v0.18.0
gotest.tools/v3 v3.5.1
)

require (
github.com/beorn7/perks v1.0.1 // indirect
github.com/cactus/tai64 v1.0.2 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
github.com/google/go-cmp v0.6.0 // indirect
github.com/google/pprof v0.0.0-20231101202521-4ca4178f5c7a // indirect
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect
github.com/onsi/ginkgo/v2 v2.13.0 // indirect
github.com/prometheus/client_model v0.5.0 // indirect
github.com/prometheus/procfs v0.12.0 // indirect
github.com/quic-go/qpack v0.4.0 // indirect
github.com/quic-go/qtls-go1-20 v0.4.1 // indirect
go.uber.org/mock v0.3.0 // indirect
golang.org/x/crypto v0.15.0 // indirect
golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect
golang.org/x/mod v0.14.0 // indirect
golang.org/x/sys v0.14.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/tools v0.15.0 // indirect
google.golang.org/protobuf v1.31.0 // indirect
)
33 changes: 30 additions & 3 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,25 @@ github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/pprof v0.0.0-20231101202521-4ca4178f5c7a h1:fEBsGL/sjAuJrgah5XqmmYsTLzJp/TO9Lhy39gkverk=
github.com/google/pprof v0.0.0-20231101202521-4ca4178f5c7a/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik=
github.com/jessevdk/go-flags v1.5.0 h1:1jKYvbxEjfUl0fmqTCOfonvskHHXMjBySTLW4y9LFvc=
github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4=
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg=
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k=
github.com/onsi/ginkgo/v2 v2.13.0 h1:0jY9lJquiL8fcf3M4LAXN5aMlS/b2BV86HFFPCPMgE4=
github.com/onsi/ginkgo/v2 v2.13.0/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xlT/ETL/o=
github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v1.17.0 h1:rl2sfwZMtSthVU752MqfjQozy7blglC+1SOtjMAMh+Q=
Expand All @@ -27,23 +37,38 @@ github.com/prometheus/common v0.45.0 h1:2BGz0eBc2hdMDLnO/8n0jeB3oPrt2D08CekT0lne
github.com/prometheus/common v0.45.0/go.mod h1:YJmSTw9BoKxJplESWWxlbyttQR4uaEcGyv9MZjVOJsY=
github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo=
github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A=
github.com/quic-go/qtls-go1-20 v0.4.1 h1:D33340mCNDAIKBqXuAvexTNMUByrYmFYVfKfDN5nfFs=
github.com/quic-go/qtls-go1-20 v0.4.1/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k=
github.com/quic-go/quic-go v0.40.0 h1:GYd1iznlKm7dpHD7pOVpUvItgMPo/jrMgDWZhMCecqw=
github.com/quic-go/quic-go v0.40.0/go.mod h1:PeN7kuVJ4xZbxSv/4OX6S1USOX8MJvydwpTx31vx60c=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/xlab/treeprint v1.2.0 h1:HzHnuAF1plUN2zGlAFHbSQP2qJ0ZAD3XF5XD7OesXRQ=
github.com/xlab/treeprint v1.2.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
go.uber.org/mock v0.3.0 h1:3mUxI1No2/60yUYax92Pt8eNOEecx2D3lcXZh2NEZJo=
go.uber.org/mock v0.3.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA=
golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g=
golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI=
golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI=
golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0=
golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg=
golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
Expand All @@ -68,14 +93,16 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA=
golang.org/x/tools v0.15.0 h1:zdAyfUGbYmuVokhzVmghFl2ZJh5QhcfebBgmVPFYA+8=
golang.org/x/tools v0.15.0/go.mod h1:hpksKq4dtpQWS1uQ61JkdqWM3LscIS6Slf+VVkm+wQk=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gotest.tools/v3 v3.5.0/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU=
gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU=
gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU=

0 comments on commit 59a4227

Please sign in to comment.