A route may have its own listener: every request there is that route, paths unprefixed
Implemented-By: OpenCode session (model recorded in docs/implementer-log.md)
This commit is contained in:
+69
-8
@@ -11,6 +11,7 @@ import (
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
"sort"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
@@ -94,21 +95,56 @@ func run() error {
|
||||
p := proxy.New(cfg, table, leases, lim, st, log)
|
||||
p.SetWaker(waker)
|
||||
|
||||
var handler http.Handler = p
|
||||
// Identity: gate the proxy on the route's peers when a backend is
|
||||
// configured; off leaves the proxy unwrapped. The same checker gates each
|
||||
// route's dedicated listener.
|
||||
logIdentityMode(log, cfg.Identity)
|
||||
|
||||
var checker *identity.Checker
|
||||
if cfg.Identity != "off" {
|
||||
var checker *identity.Checker
|
||||
switch cfg.Identity {
|
||||
case "tailscale":
|
||||
checker = identity.NewChecker(identity.TailscaleResolver{})
|
||||
default: // "header"
|
||||
checker = identity.NewHeaderChecker()
|
||||
}
|
||||
}
|
||||
var handler http.Handler = p
|
||||
if checker != nil {
|
||||
handler = identity.Middleware(checker, func(route string) ([]string, bool) {
|
||||
rt, _, ok := cfg.Route(route)
|
||||
return rt.Peers, ok
|
||||
}, p)
|
||||
}
|
||||
|
||||
// Routes with a dedicated listener each serve their own address, with every request there being
|
||||
// that route and the path unprefixed. In sorted route order, one server each, the proxy's
|
||||
// ForRoute handler wrapped in RouteMiddleware when identity is on. No admin mux on them.
|
||||
type routeServer struct {
|
||||
route string
|
||||
srv *http.Server
|
||||
}
|
||||
var routes []routeServer
|
||||
listens := make([]string, 0, len(cfg.Routes))
|
||||
for name := range cfg.Routes {
|
||||
if cfg.Routes[name].Listen != "" {
|
||||
listens = append(listens, name)
|
||||
}
|
||||
}
|
||||
sort.Strings(listens)
|
||||
for _, name := range listens {
|
||||
rt := cfg.Routes[name]
|
||||
var h http.Handler = p.ForRoute(name)
|
||||
if checker != nil {
|
||||
h = identity.RouteMiddleware(checker, rt.Peers, h)
|
||||
}
|
||||
routes = append(routes, routeServer{route: name, srv: &http.Server{
|
||||
Addr: rt.Listen,
|
||||
Handler: h,
|
||||
ReadHeaderTimeout: 10 * time.Second,
|
||||
}})
|
||||
}
|
||||
|
||||
mux := http.NewServeMux()
|
||||
mux.Handle("/_crossbar/", admin.Handler(cfg, table, leases, lim, st, hosts))
|
||||
mux.Handle("/", handler)
|
||||
@@ -173,22 +209,47 @@ func run() error {
|
||||
ReadHeaderTimeout: 10 * time.Second,
|
||||
}
|
||||
|
||||
serverErr := make(chan error, 1)
|
||||
go func() {
|
||||
log.Info("listening", "addr", srv.Addr)
|
||||
serverErr <- srv.ListenAndServe()
|
||||
}()
|
||||
// Every listener shuts down together on ctx done; the first error other than a clean shutdown
|
||||
// ends run and shuts the rest down.
|
||||
servers := make([]*http.Server, 0, 1+len(routes))
|
||||
servers = append(servers, srv)
|
||||
for i := range routes {
|
||||
servers = append(servers, routes[i].srv)
|
||||
}
|
||||
serverErr := make(chan error, len(servers))
|
||||
start := func(s *http.Server, route string) {
|
||||
go func() {
|
||||
if route != "" {
|
||||
log.Info("listening", "addr", s.Addr, "route", route)
|
||||
} else {
|
||||
log.Info("listening", "addr", s.Addr)
|
||||
}
|
||||
serverErr <- s.ListenAndServe()
|
||||
}()
|
||||
}
|
||||
start(srv, "")
|
||||
for _, rs := range routes {
|
||||
start(rs.srv, rs.route)
|
||||
}
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
log.Info("shutting down")
|
||||
shutdownCtx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
return srv.Shutdown(shutdownCtx)
|
||||
for _, s := range servers {
|
||||
_ = s.Shutdown(shutdownCtx)
|
||||
}
|
||||
return nil
|
||||
case err := <-serverErr:
|
||||
if errors.Is(err, http.ErrServerClosed) {
|
||||
return nil
|
||||
}
|
||||
shutdownCtx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
for _, s := range servers {
|
||||
_ = s.Shutdown(shutdownCtx)
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user