diff --git a/serverutil/http.go b/serverutil/http.go index 7797ae66014d20d00625e91639f9a727a44c3e39..84faef94bd5ea0a8cdbcee63108186e91bc6b0c7 100644 --- a/serverutil/http.go +++ b/serverutil/http.go @@ -20,43 +20,63 @@ var gracefulShutdownTimeout = 3 * time.Second type ServerConfig struct { TLS *TLSServerConfig `yaml:"tls"` MaxInflightRequests int `yaml:"max_inflight_requests"` + TrustedForwarders []string `yaml:"trusted_forwarders"` } -// Serve HTTP(S) content on the specified address. If serverConfig is -// not nil, enable HTTPS and TLS authentication. -// -// This function will return an error if there are problems creating -// the listener, otherwise it will handle graceful termination on -// SIGINT or SIGTERM and return nil. -func Serve(h http.Handler, serverConfig *ServerConfig, addr string) (err error) { +func (config *ServerConfig) buildHTTPServer(h http.Handler, addr string) (*http.Server, error) { var tlsConfig *tls.Config - if serverConfig != nil { - if serverConfig.TLS != nil { - tlsConfig, err = serverConfig.TLS.TLSConfig() + var err error + if config != nil { + if config.TLS != nil { + tlsConfig, err = config.TLS.TLSConfig() if err != nil { - return err + return nil, err } - h, err = serverConfig.TLS.TLSAuthWrapper(h) + h, err = config.TLS.TLSAuthWrapper(h) + if err != nil { + return nil, err + } + } + + // If TrustedForwarders is defined, rewrite the request + // headers using X-Forwarded-Proto and X-Real-IP. + if len(config.TrustedForwarders) > 0 { + h, err = newProxyHeaders(h, config.TrustedForwarders) if err != nil { - return err + return nil, err } } - if serverConfig.MaxInflightRequests > 0 { - h = newLoadSheddingWrapper(serverConfig.MaxInflightRequests, h) + // If MaxInflightRequests is set, enable the load + // shedding wrapper. + if config.MaxInflightRequests > 0 { + h = newLoadSheddingWrapper(config.MaxInflightRequests, h) } } // These are not meant to be external-facing servers, so we // can be generous with the timeouts to keep the number of // reconnections low. - srv := &http.Server{ + return &http.Server{ Addr: addr, Handler: instrumentHandler(h), ReadTimeout: 30 * time.Second, WriteTimeout: 30 * time.Second, IdleTimeout: 600 * time.Second, TLSConfig: tlsConfig, + }, nil +} + +// Serve HTTP(S) content on the specified address. If config.TLS is +// not nil, enable HTTPS and TLS authentication. +// +// This function will return an error if there are problems creating +// the listener, otherwise it will handle graceful termination on +// SIGINT or SIGTERM and return nil. +func Serve(h http.Handler, config *ServerConfig, addr string) error { + srv, err := config.buildHTTPServer(h, addr) + if err != nil { + return err } // Install a signal handler for gentle process termination. @@ -80,7 +100,7 @@ func Serve(h http.Handler, serverConfig *ServerConfig, addr string) (err error) }() signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM) - if tlsConfig != nil { + if srv.TLSConfig != nil { err = srv.ListenAndServeTLS("", "") } else { err = srv.ListenAndServe()