func serve(ctx context.Context) {
	err := server.Serve(listener)
	select {
	case _ = <-ctx.Done():
	default:
		log.Error().Str("module", "web").Str("phase", "startup").Err(err).
			Msg("HTTP server failed")
		emergencyShutdown()
		return
	}
}
serve begins serving HTTP requests
package web
import (
	"context"
	"encoding/json"
	"expvar"
	"html/template"
	"net"
	"net/http"
	"net/http/pprof"
	"net/url"
	"os"
	"path/filepath"
	"time"
	"github.com/gorilla/mux"
	"github.com/inbucket/inbucket/pkg/config"
	"github.com/inbucket/inbucket/pkg/message"
	"github.com/inbucket/inbucket/pkg/msghub"
	"github.com/inbucket/inbucket/pkg/stringutil"
	"github.com/rs/zerolog/log"
)
var (
	msgHub  *msghub.Hub
	manager message.Manager
	Router = mux.NewRouter()
	rootConfig     *config.Root
	server         *http.Server
	listener       net.Listener
	globalShutdown chan bool
	ExpWebSocketConnectsCurrent = new(expvar.Int)
)
func init() {
	m := expvar.NewMap("http")
	m.Set("WebSocketConnectsCurrent", ExpWebSocketConnectsCurrent)
}
func Initialize(
	conf *config.Root,
	shutdownChan chan bool,
	mm message.Manager,
	mh *msghub.Hub) {
	rootConfig = conf
	globalShutdown = shutdownChan
	msgHub = mh
	manager = mm
	prefix := stringutil.MakePathPrefixer(conf.Web.BasePath)
	redirectBase := prefix("/")
	if redirectBase != "/" {
		log.Info().Str("module", "web").Str("phase", "startup").Str("path", redirectBase).
			Msg("Base path configured")
		Router.Path("/").Handler(http.RedirectHandler(redirectBase, http.StatusFound))
	}
	log.Info().Str("module", "web").Str("phase", "startup").Str("path", conf.Web.UIDir).
		Msg("Web UI content mapped")
	Router.Handle(prefix("/debug/vars"), expvar.Handler())
	if conf.Web.PProf {
		Router.HandleFunc(prefix("/debug/pprof/cmdline"), pprof.Cmdline)
		Router.HandleFunc(prefix("/debug/pprof/profile"), pprof.Profile)
		Router.HandleFunc(prefix("/debug/pprof/symbol"), pprof.Symbol)
		Router.HandleFunc(prefix("/debug/pprof/trace"), pprof.Trace)
		Router.PathPrefix(prefix("/debug/pprof/")).HandlerFunc(pprof.Index)
		log.Warn().Str("module", "web").Str("phase", "startup").
			Msg("Go pprof tools installed to " + prefix("/debug/pprof"))
	}
	Router.PathPrefix(prefix("/static")).Handler(
		http.StripPrefix(prefix("/"), http.FileServer(http.Dir(conf.Web.UIDir))))
	Router.Path(prefix("/favicon.png")).Handler(
		fileHandler(filepath.Join(conf.Web.UIDir, "favicon.png")))
	indexPath := filepath.Join(conf.Web.UIDir, "index.html")
	indexTmpl, err := template.ParseFiles(indexPath)
	if err != nil {
		msg := "Failed to parse HTML template"
		cwd, _ := os.Getwd()
		log.Error().
			Str("module", "web").
			Str("phase", "startup").
			Str("path", indexPath).
			Str("cwd", cwd).
			Err(err).
			Msg(msg)
		indexTmpl, _ = template.New("index.html").Parse(msg)
	}
	spaHandler := cookieHandler(appConfigCookie(conf.Web),
		spaTemplateHandler(indexTmpl, prefix("/"), conf.Web))
	Router.Path(prefix("/")).Handler(spaHandler)
	Router.Path(prefix("/monitor")).Handler(spaHandler)
	Router.Path(prefix("/status")).Handler(spaHandler)
	Router.PathPrefix(prefix("/m/")).Handler(spaHandler)
	Router.NotFoundHandler = noMatchHandler(
		http.StatusNotFound, "No route matches URI path")
	Router.MethodNotAllowedHandler = noMatchHandler(
		http.StatusMethodNotAllowed, "Method not allowed for URI path")
}
func Start(ctx context.Context) {
	server = &http.Server{
		Addr:         rootConfig.Web.Addr,
		Handler:      requestLoggingWrapper(Router),
		ReadTimeout:  60 * time.Second,
		WriteTimeout: 60 * time.Second,
	}
	log.Info().Str("module", "web").Str("phase", "startup").Str("addr", server.Addr).
		Msg("HTTP listening on tcp4")
	var err error
	listener, err = net.Listen("tcp", server.Addr)
	if err != nil {
		log.Error().Str("module", "web").Str("phase", "startup").Err(err).
			Msg("HTTP failed to start TCP4 listener")
		emergencyShutdown()
		return
	}
	go serve(ctx)
	select {
	case _ = <-ctx.Done():
		log.Debug().Str("module", "web").Str("phase", "shutdown").
			Msg("HTTP server shutting down on request")
	}
	if err := listener.Close(); err != nil {
		log.Debug().Str("module", "web").Str("phase", "shutdown").Err(err).
			Msg("Failed to close HTTP listener")
	}
}
func appConfigCookie(webConfig config.Web) *http.Cookie {
	o := &jsonAppConfig{
		BasePath:       webConfig.BasePath,
		MonitorVisible: webConfig.MonitorVisible,
	}
	b, err := json.Marshal(o)
	if err != nil {
		log.Error().Str("module", "web").Str("phase", "startup").Err(err).
			Msg("Failed to convert app-config to JSON")
	}
	return &http.Cookie{
		Name:  "app-config",
		Value: url.PathEscape(string(b)),
		Path:  "/",
	}
}