Repository: gofiber/fiber
File: middleware/adaptor/adaptor.go (Go)

Code before:

const bufferSize = 32 * 1024

var bufferPool = sync.Pool{
	New: func() any {
		return new([bufferSize]byte)
	},
}

var (
	ErrRemoteAddrEmpty   = errors.New("remote address cannot be empty")
	ErrRemoteAddrTooLong = errors.New("remote address too long")
)

// HTTPHandlerFunc wraps net/http handler func to fiber handler
func HTTPHandlerFunc(h http.HandlerFunc) fiber.Handler {
	return HTTPHandler(h)
}

// HTTPHandler wraps net/http handler to fiber handler
func HTTPHandler(h http.Handler) fiber.Handler {
	handler := fasthttpadaptor.NewFastHTTPHandler(h)
	return func(c fiber.Ctx) error {
		// Store the Fiber user context (c.Context()) in the fasthttp request context
		// so adapted net/http handlers can retrieve it via r.Context().Value(LocalContextKey)
		c.RequestCtx().SetUserValue(LocalContextKey, c.Context())

		handler(c.RequestCtx())
		return nil
	}
}

// ConvertRequest converts a fiber.Ctx to a http.Request.
// forServer should be set to true when the http.Request is going to be passed to a http.Handler.
func ConvertRequest(c fiber.Ctx, forServer bool) (*http.Request, error) {
	var req http.Request
	if err := fasthttpadaptor.ConvertRequest(c.RequestCtx(), &req, forServer); err != nil {
		return nil, err //nolint:wrapcheck // This must not be wrapped
	}
	return &req, nil
}

// CopyContextToFiberContext copies the values of context.Context to a fasthttp.RequestCtx.
// This function safely handles struct fields, using unsafe operations only when necessary for unexported fields.
//
// Deprecated: This function uses reflection and unsafe pointers; consider using explicit context passing.
func CopyContextToFiberContext(src any, requestContext *fasthttp.RequestCtx) {
	v := reflect.ValueOf(src)
	if !v.IsValid() {
		return
	}

Review comment (performance):
```txt
goos: darwin
goarch: arm64
pkg: github.com/gofiber/fiber/v3/middleware/adaptor
cpu: Apple M4
             │ bench_old.txt │         bench_new.txt         │
             │    sec/op     │   sec/op     vs base          │
_HTTPHandler    897.4n ± 22%   931.2n ± 9%  ~ (p=0.853 n=10)

             │ bench_old.txt │          bench_new.txt           │
             │     B/op      │     B/op      vs base            │
_HTTPHandler    1.773Ki ± 0%   1.773Ki ± 0%  ~ (p=1.000 n=10) ¹
¹ all samples are equal

             │ bench_old.txt │         bench_new.txt          │
             │   allocs/op   │ allocs/op   vs base            │
_HTTPHandler      18.00 ± 0%   18.00 ± 0%  ~ (p=1.000 n=10) ¹
¹ all samples are equal
```

Your benchmark showed that the middleware became 40ns slower as a result.

Can you see if it's possible to minimize this by only setting it when it's needed or using other options?

If not, it wouldn't be a big deal, but it would be cool if it didn't degrade performance for everyone using the function, even if they don't use any context at all.

Code after:
var localContextKey = &struct{}{}

const bufferSize = 32 * 1024

var bufferPool = sync.Pool{
	New: func() any {
		return new([bufferSize]byte)
	},
}

var (
	ErrRemoteAddrEmpty   = errors.New("remote address cannot be empty")
	ErrRemoteAddrTooLong = errors.New("remote address too long")
)

// HTTPHandlerFunc wraps net/http handler func to fiber handler
func HTTPHandlerFunc(h http.HandlerFunc) fiber.Handler {
	return HTTPHandler(h)
}

// HTTPHandler wraps net/http handler to fiber handler
func HTTPHandler(h http.Handler) fiber.Handler {
	handler := fasthttpadaptor.NewFastHTTPHandler(h)
	return func(c fiber.Ctx) error {
		handler(c.RequestCtx())
		return nil
	}
}

// HTTPHandlerWithContext is like HTTPHandler, but additionally stores Fiber’s user context in the request context
func HTTPHandlerWithContext(h http.Handler) fiber.Handler {
	handler := fasthttpadaptor.NewFastHTTPHandler(h)
	return func(c fiber.Ctx) error {
		// Store the Fiber user context (c.Context()) in the fasthttp request context
		// so adapted net/http handlers can retrieve it via adaptor.LocalContextFromHTTPRequest(r)
		c.RequestCtx().SetUserValue(localContextKey, c.Context())

		handler(c.RequestCtx())
		return nil
	}
}

// LocalContextFromHTTPRequest extracts the Fiber user context previously stored into r.Context() by the adaptor.
func LocalContextFromHTTPRequest(r *http.Request) (context.Context, bool) {
	ctx, err := r.Context().Value(localContextKey).(context.Context)
	return ctx, err
}

// ConvertRequest converts a fiber.Ctx to a http.Request.
// forServer should be set to true when the http.Request is going to be passed to a http.Handler.
func ConvertRequest(c fiber.Ctx, forServer bool) (*http.Request, error) {