package httputil import ( "net/http" ) // Instrumenter wraps a handler with per-route instrumentation. The route is // the ServeMux pattern the handler is registered under; it is passed // explicitly because the pattern ServeMux records on a request is not // visible to middleware wrapping the mux from the outside. type Instrumenter func(route string, h http.Handler) http.Handler // Router is a thin layer over http.ServeMux that applies an Instrumenter to // every route and knows how to answer unrouted requests the Matrix way. // // Patterns use Go 1.22 syntax, method included: // // r.HandleFunc("GET /_matrix/client/versions", versions) type Router struct { mux *http.ServeMux instrument Instrumenter } // NewRouter returns a router. A nil Instrumenter means no instrumentation. func NewRouter(instrument Instrumenter) *Router { if instrument == nil { instrument = func(_ string, h http.Handler) http.Handler { return h } } mux := http.NewServeMux() r := &Router{mux: mux, instrument: instrument} // Anything that matches no other pattern is M_UNRECOGNIZED, per the // Client-Server API's "Unsupported endpoints" rule. r.Handle("/", NotFoundHandler()) return r } // Handle registers a handler for a pattern. func (r *Router) Handle(pattern string, h http.Handler) { r.mux.Handle(pattern, r.instrument(pattern, h)) } // HandleFunc registers an error-returning handler for a pattern. func (r *Router) HandleFunc(pattern string, h Handler) { r.Handle(pattern, Wrap(h)) } // ServeHTTP implements http.Handler. func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) { r.mux.ServeHTTP(w, req) }