func healthMW(next http.Handler, path string) http.Handler {
	fn := func(w http.ResponseWriter, r *http.Request) {
		if r.Method == "GET" && strings.HasSuffix(strings.ToLower(r.URL.Path), path) {
			render.JSON(w, r, HealthInfo{Status: "ok"})
			return
		}
		next.ServeHTTP(w, r)
	}
	return http.HandlerFunc(fn)
}
healthMW intercepts requests for the given path to return a StatusOK.
package server
import (
	"context"
	"crypto/tls"
	"encoding/json"
	"errors"
	"fmt"
	"net/http"
	"strings"
	"time"
	"github.com/optimizely/agent/config"
	"github.com/optimizely/agent/pkg/middleware"
	"github.com/optimizely/agent/plugins/interceptors"
	"github.com/go-chi/render"
	"github.com/rs/zerolog"
	"github.com/rs/zerolog/log"
)
type Server struct {
	srv    *http.Server
	logger zerolog.Logger
}
type HealthInfo struct {
	Status string `json:"status,omitempty"`
}
func NewServer(name, port string, handler http.Handler, conf config.ServerConfig) (Server, error) {
	if handler == nil {
		return Server{}, fmt.Errorf(`"%s" handler is not initialized`, name)
	}
	handler = middleware.BatchRouter(conf.BatchRequests)(handler)
	handler = middleware.AllowedHosts(conf.GetAllowedHosts())(handler)
	handler = healthMW(handler, conf.HealthCheckPath)
	handler = wrapWithInterceptors(handler, conf.Interceptors)
	logger := log.With().Str("port", port).Str("name", name).Str("host", conf.Host).Logger()
	srv := &http.Server{
		Addr:         conf.Host + ":" + port,
		Handler:      handler,
		ReadTimeout:  conf.ReadTimeout,
		WriteTimeout: conf.WriteTimeout,
	}
	if conf.KeyFile != "" && conf.CertFile != "" {
		cfg, err := makeTLSConfig(conf)
		if err != nil {
			return Server{}, err
		}
		srv.TLSConfig = cfg
	}
	return Server{srv: srv, logger: logger}, nil
}
func (s Server) ListenAndServe() (err error) {
	if s.srv.TLSConfig != nil {
		s.logger.Info().Msg("Starting TLS server.")
		err = s.srv.ListenAndServeTLS("", "")
	} else {
		s.logger.Info().Msg("Starting server.")
		err = s.srv.ListenAndServe()
	}
	if !errors.Is(err, http.ErrServerClosed) {
		s.logger.Error().Err(err).Msg("Server failed.")
		return err
	}
	return nil
}
func (s Server) Shutdown() {
	s.logger.Info().Msg("Shutting down server.")
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()
	if err := s.srv.Shutdown(ctx); err != nil {
		s.logger.Error().Err(err).Msg("Failed shutdown.")
	}
}
func wrapWithInterceptors(handler http.Handler, conf config.PluginConfigs) http.Handler {
	for name, conf := range conf {
		creator, ok := interceptors.Interceptors[name]
		if !ok {
			log.Warn().Msgf("Plugin not found: %q", name)
			continue
		}
		log.Info().Str("plugin", name).Msg("Adding plugin.")
		pInstance := creator()
		if pConfig, err := json.Marshal(conf); err != nil {
			log.Warn().Err(err).Msg("Error marshaling plugin config")
			continue
		} else if err := json.Unmarshal(pConfig, pInstance); err != nil {
			log.Warn().Err(err).Msg("Error unmarshalling plugin config")
			continue
		}
		handler = pInstance.Handler()(handler)
	}
	return handler
}
func makeTLSConfig(conf config.ServerConfig) (*tls.Config, error) {
	cert, err := tls.LoadX509KeyPair(conf.CertFile, conf.KeyFile)
	if err != nil {
		return nil, err
	}
	defaultCiphers := []uint16{
		tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
		tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
		tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
		tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
	}
	ciphers := blacklistCiphers(conf.DisabledCiphers, defaultCiphers)
	return &tls.Config{
		PreferServerCipherSuites: true,
		CipherSuites:             ciphers,
		MinVersion:               tls.VersionTLS12,
		CurvePreferences: []tls.CurveID{
			tls.CurveP256,
			tls.X25519,
			tls.CurveP384,
		},
		Certificates: []tls.Certificate{cert},
	}, nil
}
func makeDefaultCiphersMap() map[string]uint16 {
	return map[string]uint16{
		"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384": tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
		"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384":   tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
		"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256": tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
		"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256":   tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
	}
}
func blacklistCiphers(blacklist []string, defaultCiphers []uint16) []uint16 {
	defaultCiphersMap := makeDefaultCiphersMap()
	blacklistCiphersMap := map[uint16]struct{}{}
	modifiedCiphers := []uint16{}
	for _, disabledCipher := range blacklist {
		if v, ok := defaultCiphersMap[disabledCipher]; ok {
			blacklistCiphersMap[v] = struct{}{}
		}
	}
	for _, cipher := range defaultCiphers {
		if _, ok := blacklistCiphersMap[cipher]; !ok {
			modifiedCiphers = append(modifiedCiphers, cipher)
		}
	}
	return modifiedCiphers
}