diff options
-rw-r--r-- | app.go | 30 | ||||
-rw-r--r-- | helpers.go | 27 | ||||
-rw-r--r-- | internal/config/config.go | 17 | ||||
-rw-r--r-- | main.go | 97 | ||||
-rw-r--r-- | server.go | 36 |
5 files changed, 23 insertions, 184 deletions
@@ -301,9 +301,9 @@ func (a *theApp) Run() { var servers []*http.Server // Listen for HTTP - for _, fd := range a.config.Listeners.HTTP { + for _, addr := range a.config.ListenHTTPStrings.Split() { s := a.listen( - fd, + addr, httpHandler, errortracking.WithField("listener", request.SchemeHTTP), withLimiter(limiter), @@ -312,14 +312,14 @@ func (a *theApp) Run() { } // Listen for HTTPS - for _, fd := range a.config.Listeners.HTTPS { + for _, addr := range a.config.ListenHTTPSStrings.Split() { tlsConfig, err := a.TLSConfig() if err != nil { log.WithError(err).Fatal("Unable to retrieve tls config") } s := a.listen( - fd, + addr, httpHandler, errortracking.WithField("listener", request.SchemeHTTPS), withLimiter(limiter), @@ -329,9 +329,9 @@ func (a *theApp) Run() { } // Listen for HTTP proxy requests - for _, fd := range a.config.Listeners.Proxy { + for _, addr := range a.config.ListenProxyStrings.Split() { s := a.listen( - fd, + addr, proxyHandler, errortracking.WithField("listener", "http proxy"), withLimiter(limiter), @@ -340,14 +340,14 @@ func (a *theApp) Run() { } // Listen for HTTPS PROXYv2 requests - for _, fd := range a.config.Listeners.HTTPSProxyv2 { + for _, addr := range a.config.ListenHTTPSProxyv2Strings.Split() { tlsConfig, err := a.TLSConfig() if err != nil { log.WithError(err).Fatal("Unable to retrieve tls config") } s := a.listen( - fd, + addr, httpHandler, errortracking.WithField("listener", "https proxy"), withLimiter(limiter), @@ -358,8 +358,8 @@ func (a *theApp) Run() { } // Serve metrics for Prometheus - if a.config.ListenMetrics != 0 { - a.listenMetricsFD(&wg, a.config.ListenMetrics) + if a.config.General.MetricsAddress != "" { + a.listenMetrics(&wg, a.config.General.MetricsAddress) } sigChan := make(chan os.Signal, 1) @@ -385,10 +385,10 @@ func (a *theApp) Run() { } } -func (a *theApp) listen(fd uintptr, h http.Handler, errTrackingOpt errortracking.CaptureOption, opts ...option) *http.Server { +func (a *theApp) listen(addr string, h http.Handler, errTrackingOpt errortracking.CaptureOption, opts ...option) *http.Server { server := &http.Server{} go func() { - if err := a.listenAndServe(server, fd, h, opts...); err != nil && !errors.Is(err, http.ErrServerClosed) { + if err := a.listenAndServe(server, addr, h, opts...); err != nil && !errors.Is(err, http.ErrServerClosed) { capturingFatal(err, errTrackingOpt) } }() @@ -396,14 +396,14 @@ func (a *theApp) listen(fd uintptr, h http.Handler, errTrackingOpt errortracking return server } -func (a *theApp) listenMetricsFD(wg *sync.WaitGroup, fd uintptr) { +func (a *theApp) listenMetrics(wg *sync.WaitGroup, addr string) { wg.Add(1) go func() { defer wg.Done() - l, err := net.FileListener(os.NewFile(fd, "[socket]")) + l, err := net.Listen("tcp", addr) if err != nil { - capturingFatal(fmt.Errorf("failed to listen on FD %d: %w", fd, err), errortracking.WithField("listener", "metrics")) + capturingFatal(fmt.Errorf("failed to listen on addr %s: %w", addr, err), errortracking.WithField("listener", "metrics")) } monitoringOpts := []monitoring.Option{ @@ -1,36 +1,9 @@ package main import ( - "net" - "os" - "gitlab.com/gitlab-org/labkit/errortracking" ) -// Be careful: if you let either of the return values get garbage -// collected by Go they will be closed automatically. -func createSocket(addr string) (net.Listener, *os.File) { - l, err := net.Listen("tcp", addr) - if err != nil { - fatal(err, "could not create socket") - } - - return l, fileForListener(l) -} - -func fileForListener(l net.Listener) *os.File { - type filer interface { - File() (*os.File, error) - } - - f, err := l.(filer).File() - if err != nil { - fatal(err, "could not find file for listener") - } - - return f -} - func capturingFatal(err error, fields ...errortracking.CaptureOption) { fields = append(fields, errortracking.WithStackTrace()) errortracking.Capture(err, fields...) diff --git a/internal/config/config.go b/internal/config/config.go index c29fa65d..d5316bb2 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -20,18 +20,11 @@ type Config struct { ArtifactsServer ArtifactsServer Authentication Auth GitLab GitLab - Listeners Listeners Log Log Sentry Sentry TLS TLS Zip ZipServing - // Fields used to share information between files. These are not directly - // set by command line flags, but rather populated based on info from them. - // ListenMetrics points to a file descriptor of a socket, whose address is - // specified by `Config.General.MetricsAddress`. - ListenMetrics uintptr - // These fields contain the raw strings passed for listen-http, // listen-https, listen-proxy and listen-https-proxyv2 settings. It is used // by appmain() to create listeners, and the pointers to these listeners @@ -111,15 +104,6 @@ type GitLab struct { EnableDisk bool } -// Listeners groups settings related to configuring various listeners -// (HTTP, HTTPS, Proxy, HTTPSProxyv2) -type Listeners struct { - HTTP []uintptr - HTTPS []uintptr - Proxy []uintptr - HTTPSProxyv2 []uintptr -} - // Log groups settings related to configuring logging type Log struct { Format string @@ -251,7 +235,6 @@ func loadConfig() (*Config, error) { ListenHTTPSStrings: listenHTTPS, ListenProxyStrings: listenProxy, ListenHTTPSProxyv2Strings: listenHTTPSProxyv2, - Listeners: Listeners{}, } var err error @@ -2,7 +2,6 @@ package main import ( "fmt" - "io" "math/rand" "os" "time" @@ -75,105 +74,9 @@ func appMain() { fatal(err, "could not change directory into pagesRoot") } - for _, cs := range [][]io.Closer{ - createAppListeners(config), - createMetricsListener(config), - } { - defer closeAll(cs) - } - runApp(config) } -func closeAll(cs []io.Closer) { - for _, c := range cs { - c.Close() - } -} - -// createAppListeners returns net.Listener and *os.File instances. The -// caller must ensure they don't get closed or garbage-collected (which -// implies closing) too soon. -func createAppListeners(config *cfg.Config) []io.Closer { - var closers []io.Closer - var httpListeners []uintptr - var httpsListeners []uintptr - var proxyListeners []uintptr - var httpsProxyv2Listeners []uintptr - - for _, addr := range config.ListenHTTPStrings.Split() { - l, f := createSocket(addr) - closers = append(closers, l, f) - - log.WithFields(log.Fields{ - "listener": addr, - }).Debug("Set up HTTP listener") - - httpListeners = append(httpListeners, f.Fd()) - } - - for _, addr := range config.ListenHTTPSStrings.Split() { - l, f := createSocket(addr) - closers = append(closers, l, f) - - log.WithFields(log.Fields{ - "listener": addr, - }).Debug("Set up HTTPS listener") - - httpsListeners = append(httpsListeners, f.Fd()) - } - - for _, addr := range config.ListenProxyStrings.Split() { - l, f := createSocket(addr) - closers = append(closers, l, f) - - log.WithFields(log.Fields{ - "listener": addr, - }).Debug("Set up proxy listener") - - proxyListeners = append(proxyListeners, f.Fd()) - } - - for _, addr := range config.ListenHTTPSProxyv2Strings.Split() { - l, f := createSocket(addr) - closers = append(closers, l, f) - - log.WithFields(log.Fields{ - "listener": addr, - }).Debug("Set up https proxyv2 listener") - - httpsProxyv2Listeners = append(httpsProxyv2Listeners, f.Fd()) - } - - config.Listeners = cfg.Listeners{ - HTTP: httpListeners, - HTTPS: httpsListeners, - Proxy: proxyListeners, - HTTPSProxyv2: httpsProxyv2Listeners, - } - - return closers -} - -// createMetricsListener returns net.Listener and *os.File instances. The -// caller must ensure they don't get closed or garbage-collected (which -// implies closing) too soon. -func createMetricsListener(config *cfg.Config) []io.Closer { - addr := config.General.MetricsAddress - if addr == "" { - return nil - } - - l, f := createSocket(addr) - config.ListenMetrics = f.Fd() - - log.WithFields(log.Fields{ - "listener": addr, - }).Debug("Set up metrics listener") - - return []io.Closer{l, f} -} - func printVersion(showVersion bool, version string) { if showVersion { fmt.Fprintf(os.Stdout, "%s\n", version) @@ -1,11 +1,11 @@ package main import ( + "context" "crypto/tls" "fmt" "net" "net/http" - "os" "time" proxyproto "github.com/pires/go-proxyproto" @@ -13,35 +13,13 @@ import ( "gitlab.com/gitlab-org/gitlab-pages/internal/netutil" ) -type keepAliveListener struct { - net.Listener -} - -type keepAliveSetter interface { - SetKeepAlive(bool) error - SetKeepAlivePeriod(time.Duration) error -} - type listenerConfig struct { isProxyV2 bool tlsConfig *tls.Config limiter *netutil.Limiter } -func (ln *keepAliveListener) Accept() (net.Conn, error) { - conn, err := ln.Listener.Accept() - if err != nil { - return nil, err - } - - kc := conn.(keepAliveSetter) - kc.SetKeepAlive(true) - kc.SetKeepAlivePeriod(3 * time.Minute) - - return conn, nil -} - -func (a *theApp) listenAndServe(server *http.Server, fd uintptr, h http.Handler, opts ...option) error { +func (a *theApp) listenAndServe(server *http.Server, addr string, h http.Handler, opts ...option) error { config := &listenerConfig{} for _, opt := range opts { @@ -58,17 +36,19 @@ func (a *theApp) listenAndServe(server *http.Server, fd uintptr, h http.Handler, server.TLSConfig.NextProtos = append(server.TLSConfig.NextProtos, "h2") } - l, err := net.FileListener(os.NewFile(fd, "[socket]")) + lc := net.ListenConfig{ + KeepAlive: 3 * time.Minute, + } + + l, err := lc.Listen(context.Background(), "tcp", addr) if err != nil { - return fmt.Errorf("failed to listen on FD %d: %w", fd, err) + return fmt.Errorf("failed to listen on addr %s: %w", addr, err) } if config.limiter != nil { l = netutil.SharedLimitListener(l, config.limiter) } - l = &keepAliveListener{l} - if config.isProxyV2 { l = &proxyproto.Listener{ Listener: l, |