package httpx import ( "context" "net/http" ) type bridgeState struct{ parent *Context } // WrapHandler runs an existing standard handler inside the App middleware chain. // It preserves the original response, including downloads and streaming output. func WrapHandler(handler http.Handler) Handler { if handler == nil { panic("httpx: nil HTTP handler") } return func(c *Context) error { r := bridgeRequest(c) defer CleanupMultipart(r) handler.ServeHTTP(c.Raw(), r) return nil } } // WrapMiddleware adapts synchronous standard HTTP middleware. The middleware is // constructed once per chain, preserving its shared state across requests. // Errors from next are encoded before unwinding so response-transforming // middleware sees them. Preserve the incoming request context (derive with // WithContext), and never call next after ServeHTTP returns, as with net/http. func WrapMiddleware(middleware func(http.Handler) http.Handler) Middleware { if middleware == nil { panic("httpx: nil HTTP middleware") } return func(next Handler) Handler { // Each nested bridge has its own key, including repeated use of one adapter. key := &bridgeState{} wrapped := middleware(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { state, ok := r.Context().Value(key).(*bridgeState) if !ok { panic("httpx: standard middleware must preserve the incoming request context") } c := state.parent child := c.Clone(r.Context(), w) child.request = r if c.Responded() { child.writer.(interface{ inheritCommit(int) }).inheritCommit(c.Status()) } defer CleanupMultipart(r) defer func() { c.values = child.values; c.encoder = child.encoder }() if err := next(child); err != nil && !c.Responded() { child.WriteError(err) } })) if wrapped == nil { panic("httpx: HTTP middleware returned nil handler") } return func(c *Context) error { r := bridgeRequest(c).WithContext(context.WithValue(c.Context(), key, &bridgeState{parent: c})) defer CleanupMultipart(r) wrapped.ServeHTTP(c.Raw(), r) return nil } } } // WrapFuncMiddleware supports middleware shaped as func(http.HandlerFunc) http.HandlerFunc. func WrapFuncMiddleware(middleware func(http.HandlerFunc) http.HandlerFunc) Middleware { if middleware == nil { panic("httpx: nil HTTP middleware") } return WrapMiddleware(func(next http.Handler) http.Handler { return middleware(next.ServeHTTP) }) } // Populate Go 1.22 path values without mutating a parent router's request maps. func bridgeRequest(c *Context) *http.Request { r := c.Request().Clone(c.Context()) for name, value := range c.params { r.SetPathValue(name, value) } return r }