From e60d1ae5b78c80f82afcd1eaafa64b07abc2b6d0 Mon Sep 17 00:00:00 2001 From: dcarrillo Date: Mon, 20 Mar 2023 16:33:45 +0100 Subject: [PATCH] Initial server handling refactor (#9) --- cmd/whatismyip.go | 155 ++------------------------ go.mod | 18 +-- go.sum | 37 +++--- integration-tests/integration_test.go | 2 - server/quic_server.go | 54 +++++++++ server/server.go | 101 +++++++++++++++++ server/tcp_server.go | 46 ++++++++ server/tls_server.go | 47 ++++++++ 8 files changed, 284 insertions(+), 176 deletions(-) create mode 100644 server/quic_server.go create mode 100644 server/server.go create mode 100644 server/tcp_server.go create mode 100644 server/tls_server.go diff --git a/cmd/whatismyip.go b/cmd/whatismyip.go index 487b51b..62eea0e 100644 --- a/cmd/whatismyip.go +++ b/cmd/whatismyip.go @@ -2,30 +2,18 @@ package main import ( "context" - "errors" "flag" "fmt" - "log" - "net/http" "os" - "os/signal" - "syscall" "github.com/dcarrillo/whatismyip/internal/httputils" "github.com/dcarrillo/whatismyip/internal/setting" + "github.com/dcarrillo/whatismyip/server" "github.com/gin-contrib/secure" "github.com/dcarrillo/whatismyip/models" "github.com/dcarrillo/whatismyip/router" "github.com/gin-gonic/gin" - http3 "github.com/quic-go/quic-go/http3" -) - -var ( - tcpServer *http.Server - tlsServer *http.Server - h3Server *http3.Server - engine *gin.Engine ) func main() { @@ -39,149 +27,20 @@ func main() { } models.Setup(setting.App.GeodbPath.City, setting.App.GeodbPath.ASN) - setupEngine() + engine := setupEngine() router.SetupTemplate(engine) router.Setup(engine) - if setting.App.BindAddress != "" { - runTCPServer() - } - - if setting.App.TLSAddress != "" { - runTLSServer() - if setting.App.EnableHTTP3 { - runQuicServer() - } - } - - runHandler() + whatismyip := server.Setup(context.Background(), engine.Handler()) + whatismyip.Run() } -func runHandler() { - signalChan := make(chan os.Signal, 3) - signal.Notify(signalChan, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM) - ctx := context.Background() - var s os.Signal - - for { - s = <-signalChan - - if s == syscall.SIGHUP { - models.CloseDBs() - models.Setup(setting.App.GeodbPath.City, setting.App.GeodbPath.ASN) - router.SetupTemplate(engine) - - if setting.App.BindAddress != "" { - if err := tcpServer.Shutdown(ctx); err != nil { - log.Printf("TCP server forced to shutdown: %s", err) - } - runTCPServer() - } - if setting.App.TLSAddress != "" { - if setting.App.EnableHTTP3 { - if err := h3Server.Close(); err != nil { - log.Printf("QUIC server forced to shutdown") - } - } - - if err := tlsServer.Shutdown(ctx); err != nil { - log.Printf("TLS server forced to shutdown: %s", err) - } - runTLSServer() - - if setting.App.EnableHTTP3 { - runQuicServer() - } - } - } else { - log.Printf("Shutting down...") - if setting.App.BindAddress != "" { - if err := tcpServer.Shutdown(ctx); err != nil { - log.Printf("TCP server forced to shutdown: %s", err) - } - } - if setting.App.TLSAddress != "" { - if setting.App.EnableHTTP3 { - if err := h3Server.Close(); err != nil { - log.Printf("QUIC server forced to shutdown: %s", err) - } - } - if err := tlsServer.Shutdown(ctx); err != nil { - log.Printf("TLS server forced to shutdown: %s", err) - } - } - models.CloseDBs() - break - } - } -} - -func runTCPServer() { - tcpServer = &http.Server{ - Addr: setting.App.BindAddress, - Handler: engine, - ReadTimeout: setting.App.Server.ReadTimeout, - WriteTimeout: setting.App.Server.WriteTimeout, - } - - go func() { - log.Printf("Starting TCP server listening on %s", setting.App.BindAddress) - if err := tcpServer.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) { - log.Fatal(err) - } - log.Printf("Stopping TCP server...") - }() -} - -func runTLSServer() { - tlsServer = &http.Server{ - Addr: setting.App.TLSAddress, - Handler: engine, - ReadTimeout: setting.App.Server.ReadTimeout, - WriteTimeout: setting.App.Server.WriteTimeout, - } - - go func() { - log.Printf("Starting TLS server listening on %s", setting.App.TLSAddress) - if err := tlsServer.ListenAndServeTLS(setting.App.TLSCrtPath, setting.App.TLSKeyPath); err != nil && - !errors.Is(err, http.ErrServerClosed) { - log.Fatal(err) - } - log.Printf("Stopping TLS server...") - }() -} - -func runQuicServer() { - h3Server = &http3.Server{ - Addr: setting.App.TLSAddress, - Handler: tlsServer.Handler, - } - - previousHandler := tlsServer.Handler - tlsServer.Handler = http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { - if err := h3Server.SetQuicHeaders(rw.Header()); err != nil { - log.Fatal(err) - } - - previousHandler.ServeHTTP(rw, req) - }) - - go func() { - log.Printf("Starting QUIC server listening on %s (udp)", setting.App.TLSAddress) - if err := h3Server.ListenAndServeTLS(setting.App.TLSCrtPath, setting.App.TLSKeyPath); err != nil && - err.Error() != "quic: Server closed" { - log.Fatal(err) - } - log.Printf("Stopping QUIC server...") - }() -} - -func setupEngine() { +func setupEngine() *gin.Engine { gin.DisableConsoleColor() if os.Getenv(gin.EnvGinMode) == "" { gin.SetMode(gin.ReleaseMode) } - engine = gin.New() + engine := gin.New() engine.Use(gin.LoggerWithFormatter(httputils.GetLogFormatter)) engine.Use(gin.Recovery()) if setting.App.EnableSecureHeaders { @@ -193,4 +52,6 @@ func setupEngine() { } _ = engine.SetTrustedProxies(nil) engine.TrustedPlatform = setting.App.TrustedHeader + + return engine } diff --git a/go.mod b/go.mod index ddb79a0..6cb8534 100644 --- a/go.mod +++ b/go.mod @@ -9,6 +9,7 @@ require ( github.com/quic-go/quic-go v0.33.0 github.com/stretchr/testify v1.8.2 github.com/testcontainers/testcontainers-go v0.13.0 + golang.org/x/net v0.8.0 ) require ( @@ -34,8 +35,8 @@ require ( github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/mock v1.6.0 // indirect - github.com/golang/protobuf v1.5.2 // indirect - github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 // indirect + github.com/golang/protobuf v1.5.3 // indirect + github.com/google/pprof v0.0.0-20230309165930-d61513b1440d // indirect github.com/google/uuid v1.3.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/cpuid/v2 v2.2.4 // indirect @@ -48,7 +49,7 @@ require ( github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/morikuni/aec v1.0.0 // indirect - github.com/onsi/ginkgo/v2 v2.2.0 // indirect + github.com/onsi/ginkgo/v2 v2.9.1 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799 // indirect github.com/opencontainers/runc v1.1.3 // indirect @@ -56,20 +57,19 @@ require ( github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/quic-go/qpack v0.4.0 // indirect - github.com/quic-go/qtls-go1-19 v0.2.1 // indirect - github.com/quic-go/qtls-go1-20 v0.1.1 // indirect + github.com/quic-go/qtls-go1-19 v0.3.0 // indirect + github.com/quic-go/qtls-go1-20 v0.2.0 // indirect github.com/sirupsen/logrus v1.9.0 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.11 // indirect go.opencensus.io v0.23.0 // indirect golang.org/x/arch v0.3.0 // indirect golang.org/x/crypto v0.7.0 // indirect - golang.org/x/exp v0.0.0-20221205204356-47842c84f3db // indirect - golang.org/x/mod v0.8.0 // indirect - golang.org/x/net v0.8.0 // indirect + golang.org/x/exp v0.0.0-20230315142452-642cacee5cc0 // indirect + golang.org/x/mod v0.9.0 // indirect golang.org/x/sys v0.6.0 // indirect golang.org/x/text v0.8.0 // indirect - golang.org/x/tools v0.6.0 // indirect + golang.org/x/tools v0.7.0 // indirect google.golang.org/genproto v0.0.0-20220810155839-1856144b1d9c // indirect google.golang.org/grpc v1.48.0 // indirect google.golang.org/protobuf v1.30.0 // indirect diff --git a/go.sum b/go.sum index 46e0854..a679af2 100644 --- a/go.sum +++ b/go.sum @@ -317,6 +317,7 @@ github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9 github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= +github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= @@ -392,8 +393,9 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -407,7 +409,7 @@ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-containerregistry v0.5.1/go.mod h1:Ct15B4yir3PLOP5jsy0GNeYVaIZs/MK/Jz5any1wFW0= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -418,8 +420,8 @@ github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE8dj7HMvPfh66eeA2JYW7eFpSE= -github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20230309165930-d61513b1440d h1:um9/pc7tKMINFfP1eE7Wv6PRGXlcCSJkVajF7KJw3uQ= +github.com/google/pprof v0.0.0-20230309165930-d61513b1440d/go.mod h1:79YE0hCXdHag9sBkw2o+N/YnZtTkXi0UT9Nnixa5eYk= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -454,7 +456,6 @@ github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.10/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= @@ -572,8 +573,8 @@ github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+ github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= -github.com/onsi/ginkgo/v2 v2.2.0 h1:3ZNA3L1c5FYDFTTxbFeVGGD8jYvjYauHD30YgLxVsNI= -github.com/onsi/ginkgo/v2 v2.2.0/go.mod h1:MEH45j8TBi6u9BMogfbp0stKC5cdGjumZj5Y7AG4VIk= +github.com/onsi/ginkgo/v2 v2.9.1 h1:zie5Ly042PD3bsCvsSOPvRnFwyo3rKe64TJlD6nu0mk= +github.com/onsi/ginkgo/v2 v2.9.1/go.mod h1:FEcmzVcCHl+4o9bQZVab+4dC9+j+91t2FHSzmGAPfuo= github.com/onsi/gomega v0.0.0-20151007035656-2152b45fa28a/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= @@ -581,7 +582,7 @@ github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1Cpa github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc= -github.com/onsi/gomega v1.20.1 h1:PA/3qinGoukvymdIDV8pii6tiZgC8kbmJO6Z5+b002Q= +github.com/onsi/gomega v1.27.3 h1:5VwIwnBY3vbBDOJrNtA4rVdiTZCsq9B5F12pvy1Drmk= github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= @@ -658,10 +659,10 @@ github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1 github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= 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-19 v0.2.1 h1:aJcKNMkH5ASEJB9FXNeZCyTEIHU1J7MmHyz1Q1TSG1A= -github.com/quic-go/qtls-go1-19 v0.2.1/go.mod h1:ySOI96ew8lnoKPtSqx2BlI5wCpUVPT05RMAlajtnyOI= -github.com/quic-go/qtls-go1-20 v0.1.1 h1:KbChDlg82d3IHqaj2bn6GfKRj84Per2VGf5XV3wSwQk= -github.com/quic-go/qtls-go1-20 v0.1.1/go.mod h1:JKtK6mjbAVcUTN/9jZpvLbGxvdWIKS8uT7EiStoU1SM= +github.com/quic-go/qtls-go1-19 v0.3.0 h1:aUBoQdpHzUWtPw5tQZbsD2GnrWCNu7/RIX1PtqGeLYY= +github.com/quic-go/qtls-go1-19 v0.3.0/go.mod h1:ySOI96ew8lnoKPtSqx2BlI5wCpUVPT05RMAlajtnyOI= +github.com/quic-go/qtls-go1-20 v0.2.0 h1:jUHn+obJ6WI5JudqBO0Iy1ra5Vh5vsitQ1gXQvkmN+E= +github.com/quic-go/qtls-go1-20 v0.2.0/go.mod h1:JKtK6mjbAVcUTN/9jZpvLbGxvdWIKS8uT7EiStoU1SM= github.com/quic-go/quic-go v0.33.0 h1:ItNoTDN/Fm/zBlq769lLJc8ECe9gYaW40veHCCco7y0= github.com/quic-go/quic-go v0.33.0/go.mod h1:YMuhaAV9/jIu0XclDXwZPAsP/2Kgr5yMYhe9oxhhOFA= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= @@ -805,8 +806,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20221205204356-47842c84f3db h1:D/cFflL63o2KSLJIwjlcIt8PR064j/xsmdEJL/YvY/o= -golang.org/x/exp v0.0.0-20221205204356-47842c84f3db/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= +golang.org/x/exp v0.0.0-20230315142452-642cacee5cc0 h1:pVgRXcIictcr+lBQIFeiwuwtDIs4eL21OuM9nyAADmo= +golang.org/x/exp v0.0.0-20230315142452-642cacee5cc0/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -828,8 +829,8 @@ golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzB golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8= -golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.9.0 h1:KENHtAZL2y3NLMYZeHY9DW8HW8V+kQyJsY/V9JlKvCs= +golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1032,8 +1033,8 @@ golang.org/x/tools v0.0.0-20200916195026-c9a70fc28ce3/go.mod h1:z6u4i615ZeAfBE4X golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM= -golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4= +golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/integration-tests/integration_test.go b/integration-tests/integration_test.go index fdf2e9f..2716094 100644 --- a/integration-tests/integration_test.go +++ b/integration-tests/integration_test.go @@ -122,8 +122,6 @@ func TestContainerIntegration(t *testing.T) { assert.Equal(t, `h3=":8001"; ma=2592000,h3-29=":8001"; ma=2592000`, resp.Header.Get("Alt-Svc")) } } - assert.NoError(t, err) - assert.NoError(t, err) assert.Equal(t, 200, resp.StatusCode) diff --git a/server/quic_server.go b/server/quic_server.go new file mode 100644 index 0000000..b706219 --- /dev/null +++ b/server/quic_server.go @@ -0,0 +1,54 @@ +package server + +import ( + "context" + "log" + "net/http" + + "github.com/dcarrillo/whatismyip/internal/setting" + "github.com/quic-go/quic-go/http3" +) + +type QuicServer struct { + server *http3.Server + tlsServer *TLSServer + ctx context.Context +} + +func NewQuicServer(ctx context.Context, tlsServer *TLSServer) QuicServer { + return QuicServer{ + tlsServer: tlsServer, + ctx: ctx, + } +} + +func (q *QuicServer) Start() { + q.server = &http3.Server{ + Addr: setting.App.TLSAddress, + Handler: q.tlsServer.server.Handler, + } + + parentHandler := q.tlsServer.server.Handler + q.tlsServer.server.Handler = http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { + if err := q.server.SetQuicHeaders(rw.Header()); err != nil { + log.Fatal(err) + } + + parentHandler.ServeHTTP(rw, req) + }) + + log.Printf("Starting QUIC server listening on %s (udp)", setting.App.TLSAddress) + go func() { + if err := q.server.ListenAndServeTLS(setting.App.TLSCrtPath, setting.App.TLSKeyPath); err != nil && + err.Error() != "quic: Server closed" { + log.Fatal(err) + } + }() + log.Printf("Stopping QUIC server...") +} + +func (q *QuicServer) Stop() { + if err := q.server.Close(); err != nil { + log.Printf("QUIC server forced to shutdown") + } +} diff --git a/server/server.go b/server/server.go new file mode 100644 index 0000000..2d96fa6 --- /dev/null +++ b/server/server.go @@ -0,0 +1,101 @@ +package server + +import ( + "log" + "net/http" + "os" + "os/signal" + "syscall" + + "github.com/dcarrillo/whatismyip/internal/setting" + "github.com/dcarrillo/whatismyip/models" + "golang.org/x/net/context" +) + +type Server interface { + Start() + Stop() +} + +type Factory struct { + tcpServer *TCPServer + tlsServer *TLSServer + quicServer *QuicServer +} + +func Setup(ctx context.Context, handler http.Handler) *Factory { + var tcpServer TCPServer + var tlsServer TLSServer + var quicServer QuicServer + + if setting.App.BindAddress != "" { + tcpServer = NewTCPServer(ctx, &handler) + } + + if setting.App.TLSAddress != "" { + tlsServer = NewTLSServer(ctx, &handler) + if setting.App.EnableHTTP3 { + quicServer = NewQuicServer(ctx, &tlsServer) + } + } + + return &Factory{ + tcpServer: &tcpServer, + tlsServer: &tlsServer, + quicServer: &quicServer, + } +} + +func (w *Factory) Run() { + w.start() + log.Printf("Starting server handler...") + w.Watcher() +} + +func (w *Factory) Watcher() { + signalChan := make(chan os.Signal, 3) + signal.Notify(signalChan, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM) + var s os.Signal + + for { + s = <-signalChan + + if s == syscall.SIGHUP { + w.stop() + models.CloseDBs() + models.Setup(setting.App.GeodbPath.City, setting.App.GeodbPath.ASN) + w.start() + } else { + log.Printf("Shutting down...") + w.stop() + models.CloseDBs() + break + } + } +} + +func (w *Factory) start() { + if w.tcpServer != nil { + w.tcpServer.Start() + } + + if w.tlsServer != nil { + w.tlsServer.Start() + if w.quicServer != nil { + w.quicServer.Start() + } + } +} + +func (w *Factory) stop() { + if w.tcpServer != nil { + w.tcpServer.Stop() + } + + if w.tlsServer != nil { + if w.quicServer != nil { + w.quicServer.Stop() + } + w.tlsServer.Stop() + } +} diff --git a/server/tcp_server.go b/server/tcp_server.go new file mode 100644 index 0000000..5462d6c --- /dev/null +++ b/server/tcp_server.go @@ -0,0 +1,46 @@ +package server + +import ( + "context" + "errors" + "log" + "net/http" + + "github.com/dcarrillo/whatismyip/internal/setting" +) + +type TCPServer struct { + server *http.Server + handler *http.Handler + ctx context.Context +} + +func NewTCPServer(ctx context.Context, handler *http.Handler) TCPServer { + return TCPServer{ + handler: handler, + ctx: ctx, + } +} + +func (t *TCPServer) Start() { + t.server = &http.Server{ + Addr: setting.App.BindAddress, + Handler: *t.handler, + ReadTimeout: setting.App.Server.ReadTimeout, + WriteTimeout: setting.App.Server.WriteTimeout, + } + + log.Printf("Starting TCP server listening on %s", setting.App.BindAddress) + go func() { + if err := t.server.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) { + log.Fatal(err) + } + }() + log.Printf("Stopping TCP server...") +} + +func (t *TCPServer) Stop() { + if err := t.server.Shutdown(t.ctx); err != nil { + log.Printf("TCP server forced to shutdown: %s", err) + } +} diff --git a/server/tls_server.go b/server/tls_server.go new file mode 100644 index 0000000..38da79e --- /dev/null +++ b/server/tls_server.go @@ -0,0 +1,47 @@ +package server + +import ( + "context" + "errors" + "log" + "net/http" + + "github.com/dcarrillo/whatismyip/internal/setting" +) + +type TLSServer struct { + server *http.Server + handler *http.Handler + ctx context.Context +} + +func NewTLSServer(ctx context.Context, handler *http.Handler) TLSServer { + return TLSServer{ + handler: handler, + ctx: ctx, + } +} + +func (t *TLSServer) Start() { + t.server = &http.Server{ + Addr: setting.App.TLSAddress, + Handler: *t.handler, + ReadTimeout: setting.App.Server.ReadTimeout, + WriteTimeout: setting.App.Server.WriteTimeout, + } + + log.Printf("Starting TLS server listening on %s", setting.App.TLSAddress) + go func() { + if err := t.server.ListenAndServeTLS(setting.App.TLSCrtPath, setting.App.TLSKeyPath); err != nil && + !errors.Is(err, http.ErrServerClosed) { + log.Fatal(err) + } + }() + log.Printf("Stopping TLS server...") +} + +func (t *TLSServer) Stop() { + if err := t.server.Shutdown(t.ctx); err != nil { + log.Printf("TLS server forced to shutdown: %s", err) + } +}