Files
zeekayandHanzo Dev 5e3108efb2 a mounted handler streams instead of being collected
AdaptNetHTTP handed the stdlib handler fasthttp's adaptor writer, which gathers
the whole body and copies it out when the handler returns. For an ordinary reply
that is only a buffer; for server-sent events it is the difference between a
stream and one delivery at the end, so a caller watching tokens arrive saw
nothing until the answer was already complete.

The handler now runs against a pipe, and the pipe is synchronous: a Write does
not return until the reader has taken the bytes, which is what makes Flush
honest here rather than a stub. Status and headers are read from the handler's
first act and applied before the body streams, because fasthttp writes them once
and cannot revise them after.

Tested over a real socket rather than the in-memory helper — that helper collects
the whole response, so it cannot tell a stream from a buffer, which is the one
distinction these tests exist to make.

Co-authored-by: Hanzo Dev <[email protected]>
2026-08-21 01:20:24 -07:00

57 lines
2.0 KiB
Go

// Adapters for migrating existing chi / gin / net-http code onto zip
// without rewriting handlers. These are MIGRATION TOOLS — each adapter
// costs ~5% perf vs native Fiber dispatch and exists so a service can
// roll onto zip incrementally. Replace adapted routes with native
// zip handlers when feasible.
package zip
import (
"net/http"
"github.com/gofiber/fiber/v3/middleware/adaptor"
)
// AdaptNetHTTP wraps an http.Handler so it can be mounted on a zip
// router. Use for stdlib code:
//
// app.Mount("/legacy/net", zip.AdaptNetHTTP(httpHandler))
//
// Migration tool — costs ~5% perf vs native Fiber. Replace with native
// zip handlers when feasible.
func AdaptNetHTTP(h http.Handler) Handler {
// Streams — see adapt_stream.go. There is ONE adapter rather than a
// buffering one and a streaming one, because "which adapter did this route
// get" is exactly the question nobody should have to ask to explain why
// server-sent events 500 on one mount and work on another.
return adaptStreaming(h)
}
// AdaptNetHTTPFunc wraps an http.HandlerFunc.
//
// Migration tool — costs ~5% perf vs native Fiber.
func AdaptNetHTTPFunc(h http.HandlerFunc) Handler {
return adaptStreaming(h)
}
// AdaptNetHTTPMiddleware wraps a stdlib middleware (func(http.Handler) http.Handler).
//
// Migration tool — costs ~5% perf vs native Fiber.
func AdaptNetHTTPMiddleware(mw func(http.Handler) http.Handler) Handler {
wrapped := adaptor.HTTPMiddleware(mw)
return func(c *Ctx) error { return wrapped(c.fc) }
}
// Mount registers an http.Handler at the given prefix. Implicit
// chi.Router and gin.Engine support flows through AdaptNetHTTP via
// their respective ServeHTTP methods — both are http.Handlers.
//
// app.Mount("/legacy/chi", zip.AdaptNetHTTP(chiRouter))
// app.Mount("/legacy/gin", zip.AdaptNetHTTP(ginEngine))
// app.Mount("/legacy/iam", zip.AdaptNetHTTP(beegoApp.HandlerWrapper()))
//
// Migration tool — costs ~5% perf vs native Fiber.
func (a *App) Mount(prefix string, h http.Handler) {
a.All(prefix+"/*", AdaptNetHTTP(h))
}