er.
func toFiberHandler(handler any) (Handler, bool) {
	if handler == nil {
		return nil, false
	}

	switch handler.(type) {
	case Handler, func(Ctx): // (1)-(2) Fiber handlers
		return adaptFiberHandler(handler)
	case func(Req, Res) error, func(Req, Res), func(Req, Res, func() error) error, func(Req, Res, func() error), func(Req, Res, func()) error, func(Req, Res, func()), func(Req, Res, func(error)), func(Req, Res, func(error)) error, func(Req, Res, func(error) error), func(Req, Res, func(error) error) er

r)
	case fasthttp.RequestHandler, func(*fasthttp.RequestCtx) error: // (16)-(17) fasthttp handlers
		return adaptFastHTTPHandler(handler)
	default: // (18) unsupported handler type
		return nil, false
	}
}

func adaptFiberHandler(handler any) (Handler, boo

ror: // (3)-(12) Express-style request handlers
		return adaptExpressHandler(handler)
	case http.HandlerFunc, http.Handler, func(http.ResponseWriter, *http.Request): // (13)-(15) net/http handlers
		return adaptHTTPHandler(handle


 application.
// App is safe for concurrent use, except for route mutation methods that
// explicitly document otherwise.
type App struct {
	// App config
	config Config
	// Indicates if the value was explicitly configured
	configured Config
	// Ctx pool
	pool sync.Pool
	// Fasthttp server
	server *fasthttp.Server
	// Converts string to a byte slice
	toBytes func(s string) (b []byte)
	// Converts byte slice to a string
	toString func(b []byte) string
	// Hooks
	hooks *Hooks
	// Latest route & group
	latestR

age-backed)
	sharedState *SharedState
	// Route stack divided by HTTP methods
	stack [][]*Route
	// customConstraints is a list of external constraints
	customConstraints []CustomConstraint
	// sendfiles stores configurations for handling ctx.SendFile oper

oute *Route
	// newCtxFunc
	newCtxFunc func(app *App) CustomCtx
	// TLS handler
	tlsHandler *TLSHandler
	// Mount fields
	mountFields *mountFields
	// state management
	state *State
	// shared state management (prefork-safe, stor


or is an interface to register custom struct validator for binding.
type StructValidator interface {
	Validate(out any) error
}

var bindPool = sync.Pool{
	New: func() any {
		return &Bind{
			shouldSkipErrHandling: true,
		}
	},
}

// Bind provides helper methods for binding request data to Go values.
// By default (manual mode), parsing failures are returned as *BindError; use errors.As to extract source and field details.
// With WithAutoHandling(), parsing failures set HTTP 400 and return *Error instead

	BindSourceHeader     = "header"
	BindSourceCookie     = "cookie"
	BindSourceBody       = "body"
	BindSourceRespHeader = "respHeader"
)

// BindError wraps a binding failure with the source and field that failed.
// Use errors.As(err, &be) to extract it wh

.
type Bind struct {
	ctx                   Ctx
	shouldSkipErrHandling bool
	shouldSkipValidation  bool
}

// BindError source constants for BindError.Source.
const (
	BindSourceURI        = "uri"
	BindSourceQuery      = "query"


s.
type contextKey int

// userContextKey define the key name for storing context.Context in *fasthttp.RequestCtx
const (
	userContextKey contextKey = iota // __local_user_context__
)

// DefaultCtx is the default implementation of the Ctx interface
// generation tool `go install github.com/vburenin/ifacemaker@f30b6f9bdbed4b5c4804ec9ba4a04a999525c202`
// https://github.com/vburenin/ifacemaker/blob/f30b6f9bdbed4b5c4804ec9ba4a04a999525c202/ifacemaker.go#L14-L31
//
//go:generate ifacemaker --file ctx.go --file

for the request query string, parameters, body, HTTP headers and so on."
type DefaultCtx struct {
	handlerCtx             CustomCtx            // Active custom context implementation, if any
	DefaultReq                                  // Default request a

req.go --file res.go --struct DefaultCtx --iface Ctx --pkg fiber --promoted --output ctx_interface_gen.go --not-exported true --iface-comment "Ctx represents the Context which hold the HTTP request and response.\nIt has methods


sult for a single request.
// It stores the matched domain params (if any) alongside the match status
// to avoid allocating a new domainParams struct for every handler invocation.
type domainCheckResult struct {
	params    *domainParams // pre-built params (nil if no params or no match)
	isMatched bool
}

// domainMatcher holds the parsed domain pattern for matching against request hostnames.
type domainMatcher struct {
	parts      []string // domain parts split by "."
	paramIdx   []int    // indices of pa

// This prevents DoS attacks from patterns or hostnames with excessive label counts.
// RFC 1035 suggests 127 labels max, but we use a more conservative limit to prevent memory exhaustion.
const maxDomainParts = 16

// parseDomainPattern parses a domain pa

rameter parts
	paramNames []string // parameter names (without ":")
	numParts   int      // total number of parts
}

// maxDomainParts defines the maximum number of domain labels allowed (e.g., sub.domain.example.com = 4 parts).


erType, "application/pdf", "application/json"))
	require.Equal(t, "text/plain;a=1", getOffer([]byte("text/plain;a=1"), acceptsOfferType, "text/plain;a=1"))
	require.Empty(t, getOffer([]byte("text/plain;a=1;b=2"), acceptsOfferType, "text/plain;b=2"))

	// Spaces, quotes, out of order params, and case insensitivity
	require.Equal(t, "text/plain", getOffer([]byte("text/plain  "), acceptsOfferType, "text/plain"))
	require.Equal(t, "text/plain", getOffer([]byte("text/plain;q=0.4  "), acceptsOfferType, "text/plai

.Equal(t, "text/plain;b=2;a=1", getOffer([]byte("text/plain ;a=1;b=2"), acceptsOfferType, "text/plain;b=2;a=1"))
	require.Equal(t, "text/plain;a=1", getOffer([]byte("text/plain;   a=1   "), acceptsOfferType, "text/plain;a=1"))
	require.Equal(t, `text/plain

n"))
	require.Equal(t, "text/plain", getOffer([]byte("text/plain;q=0.4  ;"), acceptsOfferType, "text/plain"))
	require.Equal(t, "text/plain", getOffer([]byte("text/plain;q=0.4  ; p=foo"), acceptsOfferType, "text/plain"))
	require


string]()
)

func validateRegexHandler(handler any) any {
	if handler == nil {
		return regexp.MustCompile
	}

	handlerValue := reflect.ValueOf(handler)
	handlerType := handlerValue.Type()

	if handlerType.Kind() != reflect.Func || handlerValue.IsNil() {
		panic("fiber: Config.RegexHandler must be a non-nil function")
	}
	if handlerType.NumIn() != 1 || handlerType.In(0) != stringType || handlerType.NumOut() != 1 {
		panic("fiber: Config.RegexHandler must have signature func(string) T")
	}
	if !handlerType.O

 true
	}

	matcherValue := reflect.ValueOf(matcher)
	switch matcherValue.Kind() {
	case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Pointer, reflect.Slice:
		return matcherValue.IsNil()
	default:
		return false
	}
}

// compileRegex

ut(0).Implements(regexMatcherType) {
		panic("fiber: Config.RegexHandler return type must support MatchString(string) bool")
	}

	return handler
}

func isNilRegexMatcher(matcher regexMatcher) bool {
	if matcher == nil {
		return


	"github.com/tinylib/msgp/msgp"
)

func TestMarshalUnmarshalredirectionMsg(t *testing.T) {
	v := redirectionMsg{}
	bts, err := v.MarshalMsg(nil)
	if err != nil {
		t.Fatal(err)
	}
	left, err := v.UnmarshalMsg(bts)
	if err != nil {
		t.Fatal(err)
	}
	if len(left) > 0 {
		t.Errorf("%d bytes left over after UnmarshalMsg(): %q", len(left), left)
	}

	left, err = msgp.Skip(bts)
	if err != nil {
		t.Fatal(err)
	}
	if len(left) > 0 {
		t.Errorf("%d bytes left over after Skip(): %q", len(left), left)
	}
}

func B

onMsg{}
	bts := make([]byte, 0, v.Msgsize())
	bts, _ = v.MarshalMsg(bts[0:0])
	b.SetBytes(int64(len(bts)))
	b.ReportAllocs()
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		bts, _ = v.MarshalMsg(bts[0:0])
	}
}

func BenchmarkUnmarshalredirectionMsg(b *testin

enchmarkMarshalMsgredirectionMsg(b *testing.B) {
	v := redirectionMsg{}
	b.ReportAllocs()
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		v.MarshalMsg(nil)
	}
}

func BenchmarkAppendMsgredirectionMsg(b *testing.B) {
	v := redirecti


handler any, handlers ...any) Router
	Options(path string, handler any, handlers ...any) Router
	Trace(path string, handler any, handlers ...any) Router
	Patch(path string, handler any, handlers ...any) Router

	Add(methods []string, path string, handler any, handlers ...any) Router
	All(path string, handler any, handlers ...any) Router

	Group(prefix string, handlers ...any) Router

	Domain(host string) Router

	RouteChain(path string) Register
	Route(prefix string, fn func(router Router), name ...string)

oute struct ###
	group *Group // Group instance. used for routes in groups

	path string // Prettified path

	// Public fields
	Method string `json:"method"` // HTTP method
	Name   string `json:"name"`   // Route's name
	//nolint:revive // Having both a Pa

Router

	Name(name string) Router
}

// Route is a struct that holds all metadata for each registered handler.
type Route struct {
	// ### important: always keep in sync with the copy method "app.copyRoute" and all creations of R


rect

import (
	"regexp"
	"strconv"
	"strings"

	"github.com/gofiber/fiber/v3"
	"github.com/gofiber/utils/v2"
)

// New creates a new middleware handler
func New(config ...Config) fiber.Handler {
	cfg := configDefault(config...)

	// Initialize
	cfg.rulesRegex = map[*regexp.Regexp]string{}
	for k, v := range cfg.Rules {
		k = strings.ReplaceAll(k, "*", "(.*)")
		k += "$"
		cfg.rulesRegex[regexp.MustCompile(k)] = v
	}

	// Middleware function
	return func(c fiber.Ctx) error {
		// Next request to skip middle

Ctx().QueryArgs().QueryString())
				if queryString != "" {
					queryString = "?" + queryString
				}
				return c.Redirect().Status(cfg.StatusCode).To(replacer.Replace(v) + queryString)
			}
		}
		return c.Next()
	}
}

// https://github.com/labstack/echo

ware
		if cfg.Next != nil && cfg.Next(c) {
			return c.Next()
		}
		// Rewrite
		for k, v := range cfg.rulesRegex {
			replacer := captureTokens(k, c.Path())
			if replacer != nil {
				queryString := utils.UnsafeString(c.Request


ver //nolint:predeclared // TODO: Rename to some non-builtin

import (
	"github.com/gofiber/fiber/v3"
)

// Config defines the config for middleware.
type Config struct {
	// Next defines a function to skip this middleware when returned true.
	//
	// Optional. Default: nil
	Next func(c fiber.Ctx) bool

	// PanicHandler defines a function to customize the error produced from a recovered panic/result.
	//
	// Optional. Default: DefaultPanicHandler
	PanicHandler func(c fiber.Ctx, r any) error

	// StackTraceHa

nableStackTrace bool
}

// ConfigDefault is the default config
var ConfigDefault = Config{
	Next:              nil,
	EnableStackTrace:  false,
	StackTraceHandler: defaultStackTraceHandler,
	PanicHandler:      DefaultPanicHandler,
}

// Helper function to s

ndler defines a function to handle stack trace
	//
	// Optional. Default: defaultStackTraceHandler
	StackTraceHandler func(c fiber.Ctx, e any)

	// EnableStackTrace enables handling stack trace
	//
	// Optional. Default: false
	E


_test

import (
	"net/http"
	"net/http/httptest"
	"testing"

	"github.com/gofiber/fiber/v3"
	"github.com/gofiber/fiber/v3/middleware/skip"
	"github.com/stretchr/testify/require"
)

// go test -run Test_Skip
func Test_Skip(t *testing.T) {
	t.Parallel()
	app := fiber.New()

	app.Use(skip.New(errTeapotHandler, func(fiber.Ctx) bool { return true }))
	app.Get("/", helloWorldHandler)

	resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", http.NoBody))
	require.NoError(t, err)
	require.Equal(t, fiber.St

dHandler)

	resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", http.NoBody))
	require.NoError(t, err)
	require.Equal(t, fiber.StatusTeapot, resp.StatusCode)
}

// go test -run Test_SkipNilFunc
func Test_SkipNilFunc(t *testing.T) {
	t.Parallel(

atusOK, resp.StatusCode)
}

// go test -run Test_SkipFalse
func Test_SkipFalse(t *testing.T) {
	t.Parallel()
	app := fiber.New()

	app.Use(skip.New(errTeapotHandler, func(fiber.Ctx) bool { return false }))
	app.Get("/", helloWorl


arallel()

	app, ctx := newTestCtx(t)

	handler := func(c Ctx) {
		require.Equal(t, app, c.App())
		c.Set("X-Handler", "ok")
	}

	converted, ok := toFiberHandler(handler)
	require.True(t, ok)
	require.NotNil(t, converted)

	require.NoError(t, converted(ctx))
	require.Equal(t, "ok", string(ctx.Response().Header.Peek("X-Handler")))
}

func TestNewTestCtx_ReturnsDefaultCtx(t *testing.T) {
	t.Parallel()

	app, ctx := newTestCtx(t)
	require.NotNil(t, app)
	require.NotNil(t, ctx)
	require.Equal(t, app, ctx.App())

nup(func() {
		app.ReleaseCtx(customCtx)
	})

	return app, ctx
}

func withRouteHandlers(t *testing.T, ctx *DefaultCtx, handlers ...Handler) {
	t.Helper()

	ctx.route = &Route{Handlers: handlers}
	ctx.indexHandler = 0
	t.Cleanup(func() {
		ctx.route = nil

}

func newTestCtx(t *testing.T) (*App, *DefaultCtx) {
	t.Helper()

	app := New()
	fasthttpCtx := &fasthttp.RequestCtx{}
	customCtx := app.AcquireCtx(fasthttpCtx)
	ctx, ok := customCtx.(*DefaultCtx)
	require.True(t, ok)

	t.Clea


ol {
		conn, err := ln.Dial()
		if err != nil {
			return false
		}
		if err := conn.Close(); err != nil {
			return false
		}
		return true
	}, time.Second, 10*time.Millisecond)

	req := fasthttp.AcquireRequest()
	resp := fasthttp.AcquireResponse()

	req.SetRequestURI("http://example.com/")
	req.Header.SetMethod(fiber.MethodPost)
	req.Header.Set(fiber.HeaderOrigin, "https://example.com")
	req.SetBody(bytes.Repeat([]byte{'a'}, 32))
	if configure != nil {
		configure(req)
	}

	client := fasthttp.Client{
		Di

resp)

	t.Cleanup(func() {
		fasthttp.ReleaseResponse(respCopy)
	})

	return respCopy
}

var integrationEncryptCookieKey = encryptcookie.GenerateKey(32)

// middlewareCombinationTestCase describes a middleware stack that should keep its
// headers intact e

al: func(string) (net.Conn, error) {
			return ln.Dial()
		},
	}

	require.NoError(t, client.Do(req, resp))

	respCopy := fasthttp.AcquireResponse()
	resp.CopyTo(respCopy)

	fasthttp.ReleaseRequest(req)
	fasthttp.ReleaseResponse(


q); err != nil {
					t.Errorf("unexpected error: %v", err)
				} else {
					require.Equal(t, 200, resp.StatusCode)
				}
			}

			// Wait for normal goroutines to complete
			time.Sleep(tc.sleepTime)

			// Check final goroutine count
			finalGoroutines := runtime.NumGoroutine()
			leakedGoroutines := max(finalGoroutines-initialGoroutines, 0)
			t.Logf("[%s] Final goroutines: %d (leaked: %d)",
				tc.name, finalGoroutines, leakedGoroutines)

			if tc.expectLeak {
				// We allow up to 3x the request count

				return
			}

			// No-leak scenario: allow a small buffer for runtime noise.
			// Increase slack to reduce flakes from background goroutines.
			if leakedGoroutines > numRequests {
				t.Errorf("[%s] Expected at most %d leaked goroutines, but got %d",

 to account for noise; zero is tolerated.
				maxLeak := numRequests * 3
				if leakedGoroutines > maxLeak {
					t.Errorf("[%s] Expected at most %d leaked goroutines, but got %d",
						tc.name, maxLeak, leakedGoroutines)
				}


JSONUnmarshalTypeError", func(t *testing.T) {
		t.Parallel()
		type J struct {
			Count int `json:"count"`
		}
		app := New()
		c := app.AcquireCtx(&fasthttp.RequestCtx{})
		t.Cleanup(func() { app.ReleaseCtx(c) })
		c.Request().SetBody([]byte(`{"count":"notanint"}`))
		c.Request().Header.SetContentType(MIMEApplicationJSON)
		err := c.Bind().Body(new(J))
		require.Error(t, err)
		var be *BindError
		require.ErrorAs(t, err, &be)
		require.Equal(t, BindSourceBody, be.Source)
		require.Equal(t, "count", be.Fiel

nownKeyError{Key: "extra_field"},
			mimeType: "application/x-unknown-key-test",
		}
		app := New()
		app.RegisterCustomBinder(unknownKeyBinder)
		c := app.AcquireCtx(&fasthttp.RequestCtx{})
		t.Cleanup(func() { app.ReleaseCtx(c) })
		c.Request().SetBody([

d)
		var unmarshalErr *json.UnmarshalTypeError
		require.ErrorAs(t, err, &unmarshalErr)
	})

	t.Run("UnknownKeyError", func(t *testing.T) {
		t.Parallel()
		unknownKeyBinder := &customBinderReturningError{
			err:      schema.Unk


ON       = "application/json"
	MIMEApplicationJavaScript = "application/javascript"
	MIMEApplicationCBOR       = "application/cbor"
	MIMEApplicationForm       = "application/x-www-form-urlencoded"
	MIMEOctetStream           = "application/octet-stream"
	MIMEMultipartForm         = "multipart/form-data"
	MIMEApplicationMsgPack    = "application/vnd.msgpack"

	MIMETextXMLCharsetUTF8         = "text/xml; charset=utf-8"
	MIMETextHTMLCharsetUTF8        = "text/html; charset=utf-8"
	MIMETextPlainCharsetUTF8

EApplicationJSONCharsetUTF8 = "application/json; charset=utf-8"
)

// HTTP status codes were copied from net/http with the following updates:
// - Rename StatusNonAuthoritativeInfo to StatusNonAuthoritativeInformation
// - Add StatusSwitchProxy (306)
// NO

 = "text/plain; charset=utf-8"
	MIMETextJavaScriptCharsetUTF8  = "text/javascript; charset=utf-8"
	MIMETextCSSCharsetUTF8         = "text/css; charset=utf-8"
	MIMEApplicationXMLCharsetUTF8  = "application/xml; charset=utf-8"
	MIM


 inspired web framework written in Go with ☕
// 🤖 GitHub Repository: https://github.com/gofiber/fiber
// 📌 API Documentation: https://docs.gofiber.io

package fiber

// Colors is a struct to define custom colors for Fiber app and middlewares.
type Colors struct {
	// Black color.
	//
	// Optional. Default: "\u001b[90m"
	Black string

	// Red color.
	//
	// Optional. Default: "\u001b[91m"
	Red string

	// Green color.
	//
	// Optional. Default: "\u001b[92m"
	Green string

	// Yellow color.
	//
	// Optional.

\u001b[96m"
	Cyan string

	// White color.
	//
	// Optional. Default: "\u001b[97m"
	White string

	// Reset color.
	//
	// Optional. Default: "\u001b[0m"
	Reset string
}

// DefaultColors Default color codes
var DefaultColors = Colors{
	Black:   "\u001b[90

 Default: "\u001b[93m"
	Yellow string

	// Blue color.
	//
	// Optional. Default: "\u001b[94m"
	Blue string

	// Magenta color.
	//
	// Optional. Default: "\u001b[95m"
	Magenta string

	// Cyan color.
	//
	// Optional. Default: "


/github.com/gofiber/fiber
// 📌 API Documentation: https://docs.gofiber.io

package fiber

import (
	"github.com/valyala/fasthttp"
)

// CustomCtx extends Ctx with the additional methods required by Fiber's
// internals and middleware helpers.
type CustomCtx interface {
	Ctx

	// Reset is a method to reset context fields by given request when to use server handlers.
	Reset(fctx *fasthttp.RequestCtx)

	// release is called before returning the context to the pool.
	release()

	// Abandon marks the context as

t call ForceRelease when the handler finishes.
	Abandon()

	// IsAbandoned returns true if the context has been abandoned.
	IsAbandoned() bool

	// ForceRelease releases an abandoned context back to the pool.
	// Must only be called after the handler gorou

abandoned. An abandoned context will not be
	// returned to the pool when ReleaseCtx is called. This is used by the timeout
	// middleware to return immediately while the handler goroutine continues.
	// The cleanup goroutine mus


func Test_Ctx_Accepts_EmptyAccept(t *testing.T) {
	t.Parallel()
	app := New(Config{
		CBOREncoder: cbor.Marshal,
		CBORDecoder: cbor.Unmarshal,
	})
	c := app.AcquireCtx(&fasthttp.RequestCtx{})

	require.Equal(t, ".forwarded", c.Accepts(".forwarded"))
}

// go test -run Test_Ctx_Accepts_Wildcard
func Test_Ctx_Accepts_Wildcard(t *testing.T) {
	t.Parallel()
	app := New()
	c := app.AcquireCtx(&fasthttp.RequestCtx{})

	c.Request().Header.Set(HeaderAccept, "*/*;q=0.9")
	require.Equal(t, "html", c.Accepts("html"))

x_Accepts_MultiHeader
func Test_Ctx_Accepts_MultiHeader(t *testing.T) {
	t.Parallel()
	app := New()
	c := app.AcquireCtx(&fasthttp.RequestCtx{})

	c.Request().Header.Add(HeaderAccept, "text/plain;q=0.5")
	c.Request().Header.Add(HeaderAccept, "application/j

	require.Equal(t, "foo", c.Accepts("foo"))
	require.Equal(t, ".bar", c.Accepts(".bar"))
	c.Request().Header.Set(HeaderAccept, "text/html,application/*;q=0.9")
	require.Equal(t, "xml", c.Accepts("xml"))
}

// go test -run Test_Ct


ier.
	Context() context.Context
	// SetContext sets a context implementation by user.
	SetContext(ctx context.Context)
	// Deadline returns the time when work done on behalf of this context
	// should be canceled. Deadline returns ok==false when no deadline is
	// set. Successive calls to Deadline return the same results.
	//
	// Due to current limitations in how fasthttp works, Deadline operates as a nop.
	// See: https://github.com/valyala/fasthttp/issues/965#issuecomment-777268945
	Deadline() (time.Time,

he close of the Done channel may happen asynchronously,
	// after the cancel function returns.
	//
	// Due to current limitations in how fasthttp works, Done operates as a nop.
	// See: https://github.com/valyala/fasthttp/issues/965#issuecomment-777268945

 bool)
	// Done returns a channel that's closed when work done on behalf of this
	// context should be canceled. Done may return nil if this context can
	// never be canceled. Successive calls to Done return the same value.
	// T


p := New()

	app.Domain(":sub.:region.example.com").Get("/", func(c Ctx) error {
		sub := DomainParam(c, "sub")
		region := DomainParam(c, "region")
		return c.SendString(sub + "-" + region)
	})

	req := httptest.NewRequest(MethodGet, "/", http.NoBody)
	req.Host = "api.us-east.example.com"
	resp, err := app.Test(req)
	require.NoError(t, err)
	require.Equal(t, StatusOK, resp.StatusCode)
	body, err := io.ReadAll(resp.Body)
	require.NoError(t, err)
	require.Equal(t, "api-us-east", string(body))
}

func Test_Do

"api.example.com"
	resp, err := app.Test(req)
	require.NoError(t, err)
	require.Equal(t, StatusOK, resp.StatusCode)
	body, err := io.ReadAll(resp.Body)
	require.NoError(t, err)
	require.Equal(t, "ok", string(body))
}

func Test_Domain_ParamNameCasePreserve

main_CaseInsensitive(t *testing.T) {
	t.Parallel()

	app := New()

	app.Domain("API.Example.COM").Get("/", func(c Ctx) error {
		return c.SendString("ok")
	})

	req := httptest.NewRequest(MethodGet, "/", http.NoBody)
	req.Host =


"encoding/json"
	"errors"
	"testing"

	"github.com/gofiber/schema"
	"github.com/stretchr/testify/require"
)

func Test_ConversionError(t *testing.T) {
	t.Parallel()
	ok := errors.As(ConversionError{}, &schema.ConversionError{})
	require.True(t, ok)
}

func Test_UnknownKeyError(t *testing.T) {
	t.Parallel()
	ok := errors.As(UnknownKeyError{}, &schema.UnknownKeyError{})
	require.True(t, ok)
}

func Test_EmptyFieldError(t *testing.T) {
	t.Parallel()
	ok := errors.As(EmptyFieldError{}, &schema.EmptyFieldError{}

InvalidUnmarshalError
	ok := errors.As(&InvalidUnmarshalError{}, &e)
	require.True(t, ok)
}

func Test_MarshalerError(t *testing.T) {
	t.Parallel()
	var e *json.MarshalerError
	ok := errors.As(&MarshalerError{}, &e)
	require.True(t, ok)
}

func Test_Syntax

)
	require.True(t, ok)
}

func Test_MultiError(t *testing.T) {
	t.Parallel()
	ok := errors.As(MultiError{}, &schema.MultiError{})
	require.True(t, ok)
}

func Test_InvalidUnmarshalError(t *testing.T) {
	t.Parallel()
	var e *json.


ms
	spec        string
	quality     float64
	specificity int
	order       int
}

const noCacheValue = "no-cache"

// Pre-allocated byte slices for accept header parsing
var (
	semicolonQEquals = []byte(";q=")
	wildcardAll      = []byte("*/*")
	wildcardSuffix   = []byte("/*")
)

type headerParams map[string][]byte

// ValueFromContext retrieves a value stored under key from supported context types.
//
// Supported context types:
//   - Ctx (including CustomCtx implementations)
//   - *fasthttp.RequestCtx
//

th Fiber locals and request context.
//
// This is useful when values need to be available via both c.Locals() and
// context.Context lookups throughout middleware and handlers.
func StoreInContext(c Ctx, key, value any) {
	c.Locals(key, value)

	if c.App(

  - context.Context
//   - any value exposing UserValue(key any) any or Value(key any) any
func ValueFromContext[T any](ctx, key any) (T, bool) {
	return contextvalue.Value[T](ctx, key)
}

// StoreInContext stores key/value in bo


 this for unreachable code if panicking is undesirable (i.e., in a handler).
// Unexported because users will hopefully never need to see it.
var errUnreachable = errors.New("fiber: unreachable code, please create an issue at github.com/gofiber/fiber")

// General errors
var (
	ErrGracefulTimeout = errors.New("shutdown: graceful timeout has been reached, exiting")
	// ErrNotRunning indicates that a Shutdown method was called when the server was not running.
	ErrNotRunning = errors.New("shutdown: server is n

 that a helper requiring a view engine was invoked without one configured.
	ErrNoViewEngineConfigured = errors.New("fiber: no view engine configured")
	// ErrAutoCertWithCertFile indicates AutoCertManager cannot be used with CertFile/CertKeyFile.
	ErrAutoC

ot running")
	// ErrHandlerExited is returned by App.Test if a handler panics or calls runtime.Goexit().
	ErrHandlerExited = errors.New("runtime.Goexit() called in handler or server panic")
	// ErrNoViewEngineConfigured indicates


mt"
	"reflect"
)

// Group represents a collection of routes that share middleware and a common
// path prefix.
type Group struct {
	app         *App
	parentGroup *Group
	name        string

	Prefix      string
	hasAnyRoute bool
}

// Name Assign name to specific route or group itself.
//
// If this method is used before any route added to group, it'll set group name and OnGroupNameHook will be used.
// Otherwise, it'll set route name and OnName hook will be used.
func (grp *Group) Name(name string) Router

eHooks(*grp); err != nil {
		panic(err)
	}
	grp.app.mutex.Unlock()

	return grp
}

// Use registers a middleware route that will match requests
// with the provided prefix (which is optional and defaults to "/").
// Also, you can pass another app instance

{
	if grp.hasAnyRoute {
		grp.app.Name(name)

		return grp
	}

	grp.app.mutex.Lock()
	if grp.parentGroup != nil {
		grp.name = grp.parentGroup.name + name
	} else {
		grp.name = name
	}

	if err := grp.app.hooks.executeOnGroupNam


pHandler = func(Group) error
	// OnGroupNameHandler shares the OnGroupHandler signature for group naming callbacks.
	OnGroupNameHandler = OnGroupHandler
	// OnListenHandler runs when the application begins listening and receives the listener details.
	OnListenHandler = func(ListenData) error
	// OnPreStartupMessageHandler runs before Fiber prints the startup banner.
	OnPreStartupMessageHandler = func(*PreStartupMessageData) error
	// OnPostStartupMessageHandler runs after Fiber prints (or skips) the startup

eceives the shutdown result.
	OnPostShutdownHandler = func(error) error
	// OnForkHandler runs inside a forked worker process and receives the worker ID.
	OnForkHandler = func(int) error
	// OnMountHandler runs after a sub-application mounts to a parent an

 banner.
	OnPostStartupMessageHandler = func(*PostStartupMessageData) error
	// OnPreShutdownHandler runs before the application shuts down.
	OnPreShutdownHandler = func() error
	// OnPostShutdownHandler runs after shutdown and r


) {
	t.Parallel()
	app := New()

	app.Hooks().OnRoute(func(r Route) error {
		require.Empty(t, r.Name)

		return nil
	})

	app.Get("/", testSimpleHandler).Name("x")

	subApp := New()
	subApp.Get("/test", testSimpleHandler)

	app.Use("/sub", subApp)
}

func Test_Hook_OnRoute_Mount(t *testing.T) {
	t.Parallel()
	app := New()
	subApp := New()
	app.Use("/sub", subApp)

	subApp.Hooks().OnRoute(func(r Route) error {
		require.Equal(t, "/sub/test", r.Path)

		return nil
	})

	app.Hooks().OnRoute(func(r Route) erro

l.Get()
	defer bytebufferpool.Put(buf)

	app.Hooks().OnName(func(r Route) error {
		_, err := buf.WriteString(r.Name)
		require.NoError(t, err)

		return nil
	})

	app.Get("/", testSimpleHandler).Name("index")

	subApp := New()
	subApp.Get("/test", testSim

r {
		require.Equal(t, "/", r.Path)

		return nil
	})

	app.Get("/", testSimpleHandler).Name("x")
	subApp.Get("/test", testSimpleHandler)
}

func Test_Hook_OnName(t *testing.T) {
	t.Parallel()
	app := New()

	buf := bytebufferpoo


raceful_Shutdown
func Test_Listen_Graceful_Shutdown(t *testing.T) {
	t.Run("Basic Graceful Shutdown", func(t *testing.T) {
		testGracefulShutdown(t, 0)
	})

	t.Run("Shutdown With Timeout", func(t *testing.T) {
		testGracefulShutdown(t, 500*time.Millisecond)
	})

	t.Run("Shutdown With Timeout Error", func(t *testing.T) {
		testGracefulShutdown(t, 1*time.Nanosecond)
	})
}

func testGracefulShutdown(t *testing.T, shutdownTimeout time.Duration) {
	t.Helper()

	var mu sync.Mutex
	var shutdown bool
	var receivedE

own(func(err error) error {
		mu.Lock()
		defer mu.Unlock()
		shutdown = true
		receivedErr = err
		return nil
	})

	go func() {
		ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
		defer cancel()

		errs <- app.Listener(ln, ListenCo

rr error

	app := New()
	app.Get("/", func(c Ctx) error {
		time.Sleep(10 * time.Millisecond)
		return c.SendString(c.Hostname())
	})

	ln := fasthttputil.NewInmemoryListener()
	errs := make(chan error, 1)

	app.hooks.OnPostShutd


st(httptest.NewRequest(MethodGet, "/resource/ALLOW", http.NoBody))
	require.NoError(t, err)
	require.Equal(t, StatusOK, resp.StatusCode)

	resp, err = parent.Test(httptest.NewRequest(MethodGet, "/mounted/resource/ALLOW", http.NoBody))
	require.NoError(t, err)
	require.Equal(t, StatusOK, resp.StatusCode)

	resp, err = sub.Test(httptest.NewRequest(MethodGet, "/resource/allow", http.NoBody))
	require.NoError(t, err)
	require.Equal(t, StatusNotFound, resp.StatusCode)

	resp, err = parent.Test(httptest.NewReques

	micro.Get("/doe", func(c Ctx) error {
		return c.SendStatus(StatusOK)
	})

	app := New()
	app.Use("/john", micro)
	resp, err := app.Test(httptest.NewRequest(MethodGet, "/john/doe", http.NoBody))
	require.NoError(t, err, "app.Test(req)")
	require.Equal(t,

t(MethodGet, "/mounted/resource/allow", http.NoBody))
	require.NoError(t, err)
	require.Equal(t, StatusNotFound, resp.StatusCode)
}

// go test -run Test_App_Mount
func Test_App_Mount(t *testing.T) {
	t.Parallel()
	micro := New()


ort"
	"sync"
	"sync/atomic"

	"github.com/gofiber/utils/v2"
)

// Put fields related to mounting.
type mountFields struct {
	// Mounted and main apps
	appList map[string]*App
	// Prefix of app if it was mounted
	mountPath string
	// Ordered keys of apps (sorted by key length for Render)
	appListKeys []string
	// check added routes of sub-apps
	subAppsRoutesAdded sync.Once
	// check mounted sub-apps
	subAppsProcessed sync.Once
}

// Create empty mountFields instance
func newMountFields(app *App) *mountFields

 many independent routers and
// compose them as a single service using Mount. The fiber's error handler and
// any of the fiber's sub apps are added to the application's error handlers
// to be invoked on errors that happen within the prefix route.
func (

 {
	return &mountFields{
		appList:     map[string]*App{"": app},
		appListKeys: make([]string, 0),
	}
}

// Mount attaches another app instance as a sub-router along a routing path.
// It's very useful to split up a large API as


istenConfig struct {
	// GracefulContext is a field to shutdown Fiber by given context gracefully.
	//
	// Default: nil
	GracefulContext context.Context `json:"graceful_context"` //nolint:containedctx // It's needed to set context inside Listen.

	// PreforkLogger sets a custom logger for the prefork process manager.
	// This only applies when EnablePrefork is true.
	//
	// Default: Fiber's built-in logger (log.Infof)
	PreforkLogger PreforkLogger `json:"prefork_logger"`

	// TLSConfigFunc allows customizing

te providers via GetCertificate.
	//
	// Default: nil
	TLSConfig *tls.Config `json:"tls_config"`

	// ListenerFunc allows accessing and customizing net.Listener.
	//
	// Default: nil
	ListenerAddrFunc func(addr net.Addr) `json:"listener_addr_func"`

	// Be

 tls.Config as you want.
	//
	// Default: nil
	TLSConfigFunc func(tlsConfig *tls.Config) `json:"tls_config_func"`

	// TLSConfig allows providing a tls.Config used as the base for TLS settings.
	// This enables external certifica


: "/api/v1/something", params: nil, match: false},
			},
		},
		{
			pattern: "/api/:param/fixedEnd",
			testCases: []routeTestCase{
				{url: "/api/abc/fixedEnd", params: []string{"abc"}, match: true},
				{url: "/api/abc/def/fixedEnd", params: nil, match: false},
			},
		},
		{
			pattern: "/api/v1/:param/*",
			testCases: []routeTestCase{
				{url: "/api/v1/entity", params: []string{"entity", ""}, match: true},
				{url: "/api/v1/entity/", params: []string{"entity", ""}, match: true},
				{url: "/api/v1/

ne benchmark cases and other cases
	routeTestCases = benchmarkCases
	routeTestCases = append(
		routeTestCases,
		[]routeCaseCollection{
			{
				pattern: "/api/v1/:param/+",
				testCases: []routeTestCase{
					{url: "/api/v1/entity", params: nil, match:

entity/1", params: []string{"entity", "1"}, match: true},
				{url: "/api/v", params: nil, match: false},
				{url: "/api/v2", params: nil, match: false},
				{url: "/api/v1/", params: nil, match: false},
			},
		},
	}

	// combi


/github.com/gofiber/fiber
// 📌 API Documentation: https://docs.gofiber.io
// 💖 Maintained and modified for Fiber by @renewerner87
package fiber

import (
	"crypto/tls"
	"io"
	"os"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	"github.com/valyala/fasthttp/prefork"
)

func Test_App_Prefork_Child_Process(t *testing.T) {
	enableTestPreforkMaster(t)

	setupIsChild(t)

	app := New()

	cfg := listenConfigDefault()
	err := app.prefork("invalid", nil, &cfg)
	requir

reate tls certificate
	cer, err := tls.LoadX509KeyPair("./.github/testdata/ssl.pem", "./.github/testdata/ssl.key")
	if err != nil {
		require.NoError(t, err)
	}
	config := &tls.Config{Certificates: []tls.Certificate{cer}}

	go func() {
		time.Sleep(1000 *

e.Error(t, err)

	go func() {
		time.Sleep(1000 * time.Millisecond)
		assert.NoError(t, app.Shutdown())
	}()

	ipv6Cfg := ListenConfig{ListenerNetwork: NetworkTCP6}
	require.NoError(t, app.prefork("[::1]:", nil, &ipv6Cfg))

	// C


/v3/binder"
)

// Pool for redirection
var (
	redirectPool = sync.Pool{
		New: func() any {
			return &Redirect{
				status:   StatusSeeOther,
				messages: make(redirectionMsgs, 0),
			}
		},
	}
	oldInputPool = sync.Pool{
		New: func() any {
			return make(map[string]string)
		},
	}
)

const maxPoolableMapSize = 64

// FlashCookieName Cookie name to send flash messages when to use redirection.
const (
	FlashCookieName = "fiber_flash"
)

var flashCookieNeedle = []byte(FlashCookieName + "=")

// hasFlashCook

p to avoid prefix false positives (e.g. fiber_flashX).
func hasFlashCookie(header *fasthttp.RequestHeader) bool {
	rawHeaders := header.RawHeaders()
	if len(rawHeaders) == 0 {
		return false
	}

	if !bytes.Contains(rawHeaders, flashCookieNeedle) {
		return

ie is on the request hot path and runs on every request/response cycle.
// Keep this cheap for users who don't use flash messages:
// 1) a fast raw-header prefilter to avoid unnecessary cookie parsing,
// 2) an exact cookie looku


1},
			{Const: "/size:", Length: 6},
			{IsParam: true, ParamName: "size", IsLast: true},
		},
		params: []string{"filter", "color", "size"},
	}, rp)

	rp = parseRoute("/api/v1/:param/abc/*", regexp.MustCompile)
	require.Equal(t, routeParser{
		segs: []*routeSegment{
			{Const: "/api/v1/", Length: 8},
			{IsParam: true, ParamName: "param", ComparePart: "/abc", PartCount: 1},
			{Const: "/abc/", Length: 5, HasOptionalSlash: true},
			{IsParam: true, ParamName: "*1", IsGreedy: true, IsOptional: true, IsLast:

1/some/resource/name:customVerb", Length: 33, IsLast: true},
		},
		params: nil,
	}, rp)

	rp = parseRoute("/v1/some/resource/:name\\:customVerb", regexp.MustCompile)
	require.Equal(t, routeParser{
		segs: []*routeSegment{
			{Const: "/v1/some/resource/",

true},
		},
		params:        []string{"param", "*1"},
		wildCardCount: 1,
	}, rp)

	rp = parseRoute("/v1/some/resource/name\\:customVerb", regexp.MustCompile)
	require.Equal(t, routeParser{
		segs: []*routeSegment{
			{Const: "/v


limitMaps   = 32
)

// DecodeMsg implements msgp.Decodable
func (z *redirectionMsg) DecodeMsg(dc *msgp.Reader) (err error) {
	var field []byte
	_ = field
	var zb0001 uint32
	zb0001, err = dc.ReadMapHeader()
	if err != nil {
		err = msgp.WrapError(err)
		return
	}
	if zb0001 > zc920acdalimitMaps {
		err = msgp.ErrLimitExceeded
		return
	}
	for zb0001 > 0 {
		zb0001--
		field, err = dc.ReadMapKeyPtr()
		if err != nil {
			err = msgp.WrapError(err)
			return
		}
		switch msgp.UnsafeString(field) {
		case "key"

		case "level":
			z.level, err = dc.ReadUint8()
			if err != nil {
				err = msgp.WrapError(err, "level")
				return
			}
		case "isOldInput":
			z.isOldInput, err = dc.ReadBool()
			if err != nil {
				err = msgp.WrapError(err, "isOldInput")
				return

:
			z.key, err = dc.ReadString()
			if err != nil {
				err = msgp.WrapError(err, "key")
				return
			}
		case "value":
			z.value, err = dc.ReadString()
			if err != nil {
				err = msgp.WrapError(err, "value")
				return
			}


ub.com/valyala/fasthttp/prefork"
)

// Test seams for prefork testing - allows injecting dummy commands
var (
	testPreforkMaster = false
	testOnPrefork     = false
	dummyPid          = 1
	dummyChildCmd     atomic.Value
)

// IsChild determines if the current process is a child of Prefork
func IsChild() bool {
	return prefork.IsChild()
}

// prefork manages child processes to make use of the OS REUSEPORT feature.
// It delegates to fasthttp's prefork package to avoid duplicating process management logic.
fun

 == 0 {
		recoverThreshold = max(1, runtime.GOMAXPROCS(0)/2)
	}

	// Use configured logger or default to Fiber's log package
	var logger prefork.Logger
	if cfg.PreforkLogger != nil {
		logger = cfg.PreforkLogger
	} else {
		logger = preforkLogger{}
	}

	p

c (app *App) prefork(addr string, tlsConfig *tls.Config, cfg *ListenConfig) error {
	if cfg == nil {
		cfg = &ListenConfig{}
	}

	// Determine RecoverThreshold
	recoverThreshold := cfg.PreforkRecoverThreshold
	if recoverThreshold


New()
	c := app.AcquireCtx(&fasthttp.RequestCtx{})
	defer app.ReleaseCtx(c)

	err := c.Redirect().To("http://default.com")
	require.NoError(t, err)
	require.Equal(t, StatusSeeOther, c.Response().StatusCode())
	require.Equal(t, "http://default.com", string(c.Response().Header.Peek(HeaderLocation)))

	err = c.Redirect().Status(301).To("http://example.com")
	require.NoError(t, err)
	require.Equal(t, 301, c.Response().StatusCode())
	require.Equal(t, "http://example.com", string(c.Response().Header.Peek(HeaderLo

, "2").With("success", "1").With("message", "test", 2).To("http://example.com")
	require.NoError(t, err)
	require.Equal(t, StatusSeeOther, c.Response().StatusCode())
	require.Equal(t, "http://example.com", string(c.Response().Header.Peek(HeaderLocation)))

cation)))
}

// go test -run Test_Redirect_To_WithFlashMessages
func Test_Redirect_To_WithFlashMessages(t *testing.T) {
	t.Parallel()
	app := New()
	c := app.AcquireCtx(&fasthttp.RequestCtx{})

	err := c.Redirect().With("success"


able.
func (r *DefaultReq) AcceptsCharsets(offers ...string) string {
	header := joinHeaderValues(r.c.fasthttp.Request.Header.PeekAll(HeaderAcceptCharset))
	return getOffer(header, acceptsOffer, offers...)
}

// AcceptsEncodings checks if the specified encoding is acceptable.
func (r *DefaultReq) AcceptsEncodings(offers ...string) string {
	header := joinHeaderValues(r.c.fasthttp.Request.Header.PeekAll(HeaderAcceptEncoding))
	return getOffer(header, acceptsOffer, offers...)
}

// AcceptsLanguages checks if

rn getOffer(header, acceptsLanguageOfferBasic, offers...)
}

// AcceptsLanguagesExtended checks if the specified language is acceptable using
// RFC 4647 Extended Filtering.
func (r *DefaultReq) AcceptsLanguagesExtended(offers ...string) string {
	header :

the specified language is acceptable using
// RFC 4647 Basic Filtering.
func (r *DefaultReq) AcceptsLanguages(offers ...string) string {
	header := joinHeaderValues(r.c.fasthttp.Request.Header.PeekAll(HeaderAcceptLanguage))
	retu


pp returns the *App reference to the instance of the Fiber application
	App() *App
	// Append the specified value to the HTTP response header field.
	// If the header is not already set, it creates the header with the specified value.
	Append(field string, values ...string)
	// Attachment sets the HTTP response Content-Disposition header field to attachment.
	Attachment(filename ...string)
	// ClearCookie expires a specific cookie by key on the client side.
	// If no key is provided it expires all cookies t

Cookie sets a cookie by passing a cookie struct.
	Cookie(cookie *Cookie)
	// Download transfers the file from path as an attachment.
	// Typically, browsers will prompt the user for download.
	// By default, the Content-Disposition header filename= paramet

hat came with the request.
	ClearCookie(key ...string)
	// RequestCtx returns *fasthttp.RequestCtx that carries a deadline
	// a cancellation signal, and other values across API boundaries.
	RequestCtx() *fasthttp.RequestCtx
	//


/github.com/gofiber/fiber
// 📌 API Documentation: https://docs.gofiber.io

package fiber

// Register defines all router handle interface generate by RouteChain().
type Register interface {
	All(handler any, handlers ...any) Register
	Get(handler any, handlers ...any) Register
	Head(handler any, handlers ...any) Register
	Post(handler any, handlers ...any) Register
	Put(handler any, handlers ...any) Register
	Delete(handler any, handlers ...any) Register
	Connect(handler any, handlers ...any) Register
	Opti

ter
}

var _ Register = (*Registering)(nil)

// Registering provides route registration helpers for a specific path on the
// application instance.
type Registering struct {
	app   *App
	group *Group

	path string
}

// All registers a middleware route tha

ons(handler any, handlers ...any) Register
	Trace(handler any, handlers ...any) Register
	Patch(handler any, handlers ...any) Register

	Add(methods []string, handler any, handlers ...any) Register

	RouteChain(path string) Regis


FileStore struct {
	handler           fasthttp.RequestHandler
	cacheControlValue string
	config            SendFile
}

// configEqual compares the current SendFile config with the new one
// and returns true if they are equal.
//
// Here we don't use reflect.DeepEqual because it is quite slow compared to manual comparison.
func (sf *sendFileStore) configEqual(cfg SendFile) bool {
	if sf.config.FS != cfg.FS {
		return false
	}

	if sf.config.Compress != cfg.Compress {
		return false
	}

	if sf.config.ByteRan

eturn true
}

// Cookie defines the values used when configuring cookies emitted by
// DefaultRes.Cookie.
type Cookie struct {
	Expires     time.Time `json:"expires"`      // The expiration date of the cookie
	Name        string    `json:"name"`         //

ge != cfg.ByteRange {
		return false
	}

	if sf.config.Download != cfg.Download {
		return false
	}

	if sf.config.CacheDuration != cfg.CacheDuration {
		return false
	}

	if sf.config.MaxAge != cfg.MaxAge {
		return false
	}

	r


string) string
	// AcceptsEncodings checks if the specified encoding is acceptable.
	AcceptsEncodings(offers ...string) string
	// AcceptsLanguages checks if the specified language is acceptable using
	// RFC 4647 Basic Filtering.
	AcceptsLanguages(offers ...string) string
	// AcceptsLanguagesExtended checks if the specified language is acceptable using
	// RFC 4647 Extended Filtering.
	AcceptsLanguagesExtended(offers ...string) string
	// App returns the *App reference to the instance of the Fiber applicat

	// Make copies or use the Immutable setting instead.
	BodyRaw() []byte
	//nolint:nonamedreturns // gocritic unnamedResult prefers naming decoded body, decode count, and error
	tryDecodeBodyInOrder(originalBody *[]byte, encodings []string) (body []byte, d

ion
	App() *App
	// BaseURL returns (protocol + host + base path).
	BaseURL() string
	// BodyRaw contains the raw body submitted in a POST request.
	// Returned value is only valid within the handler. Do not store any references.


{
	// Start starts the service, returning an error if it fails.
	Start(ctx context.Context) error

	// String returns a string representation of the service.
	// It is used to print a human-readable name of the service in the startup message.
	String() string

	// State returns the current state of the service.
	State(ctx context.Context) (string, error)

	// Terminate terminates the service, returning an error if it fails.
	Terminate(ctx context.Context) error
}

// hasConfiguredServices Checks if there ar

red.Services)
}

func validateServicesSlice(services []Service) error {
	for idx, srv := range services {
		if srv == nil {
			return fmt.Errorf("fiber: service at index %d is nil", idx)
		}
	}
	return nil
}

// initServices If the app is configured to use

e any services for the current application.
func (app *App) hasConfiguredServices() bool {
	return len(app.configured.Services) > 0
}

func (app *App) validateConfiguredServices() error {
	return validateServicesSlice(app.configu


ewReader(
			"GET / HTTP/1.1\r\nHost: localhost\r\nCookie: " + cookie + "\r\n\r\n",
		)
		req := new(fasthttp.Request)
		require.NoError(t, req.Read(bufio.NewReader(rawRequest)))
		return req
	}

	req := buildRequestWithCookie(t, FlashCookieName+"X=not-the-flash-cookie")
	require.False(t, hasFlashCookie(&req.Header))

	req = buildRequestWithCookie(t, FlashCookieName+"=valid")
	require.True(t, hasFlashCookie(&req.Header))

	var syntheticReq fasthttp.Request
	syntheticReq.Header.Set(HeaderCookie, FlashCookieN

ppend(order, "fiber-before")
		c.Set("X-Fiber", "1")
		return c.Next()
	}

	httpHandler := http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
		order = append(order, "http-final")
		w.Header().Set("X-HTTP", "true")
		_, err := w.Write([]byte("

ame+"=valid")
	require.False(t, hasFlashCookie(&syntheticReq.Header))
}

func Test_Route_MixedFiberAndHTTPHandlers(t *testing.T) {
	t.Parallel()

	app := New()

	var order []string

	fiberBefore := func(c Ctx) error {
		order = a


Storage) Set(string, []byte, time.Duration) error {
	return s.err
}

func (s *errorStorage) DeleteWithContext(context.Context, string) error {
	return s.err
}

func (s *errorStorage) Delete(string) error {
	return s.err
}

func (s *errorStorage) ResetWithContext(context.Context) error {
	return s.err
}

func (s *errorStorage) Reset() error {
	return s.err
}

func (s *errorStorage) Close() error {
	return s.closeErr
}

func (s *contextCheckingStorage) SetWithContext(ctx context.Context, key string, val []byt

text, key string) ([]byte, error) {
	if ctx.Value(s.ctxKey) == nil {
		return nil, errors.New("context value not found")
	}
	return s.base.GetWithContext(ctx, key)
}

func (s *contextCheckingStorage) DeleteWithContext(ctx context.Context, key string) error

e, exp time.Duration) error {
	if ctx.Value(s.ctxKey) == nil {
		return errors.New("context value not found")
	}
	return s.base.SetWithContext(ctx, key, val, exp)
}

func (s *contextCheckingStorage) GetWithContext(ctx context.Con


etString("str")
	require.True(t, ok)
	require.Equal(t, "hello", s)

	// wrong type should return false
	st.Set("num", 123)
	s, ok = st.GetString("num")
	require.False(t, ok)
	require.Empty(t, s)

	// missing key should return false
	s, ok = st.GetString("missing")
	require.False(t, ok)
	require.Empty(t, s)
}

func TestState_GetInt(t *testing.T) {
	t.Parallel()
	st := newState()

	st.Set("num", 456)
	i, ok := st.GetInt("num")
	require.True(t, ok)
	require.Equal(t, 456, i)

	// wrong type should return zero v

State_GetBool(t *testing.T) {
	t.Parallel()
	st := newState()

	st.Set("flag", true)
	b, ok := st.GetBool("flag")
	require.True(t, ok)
	require.True(t, b)

	// wrong type
	st.Set("num", 1)
	b, ok = st.GetBool("num")
	require.False(t, ok)
	require.False(t,

alue
	st.Set("str", "abc")
	i, ok = st.GetInt("str")
	require.False(t, ok)
	require.Equal(t, 0, i)

	// missing key should return zero value
	i, ok = st.GetInt("missing")
	require.False(t, ok)
	require.Equal(t, 0, i)
}

func Test


e redirect

import (
	"regexp"

	"github.com/gofiber/fiber/v3"
)

// Config defines the config for middleware.
type Config struct {
	// Filter defines a function to skip middleware.
	// Optional. Default: nil
	Next func(fiber.Ctx) bool

	// Rules defines the URL path rewrite rules. The values captured in asterisk can be
	// retrieved by index e.g. $1, $2 and so on.
	// Required. Example:
	// "/old":              "/new",
	// "/api/*":            "/$1",
	// "/js/*":             "/public/javascript/$1",
	// "/

ct
	StatusCode int
}

// ConfigDefault is the default config
var ConfigDefault = Config{
	StatusCode: fiber.StatusFound,
}

// Helper function to set default values
func configDefault(config ...Config) Config {
	// Return default config if nothing provided

users/*/orders/*": "/user/$1/order/$2",
	Rules map[string]string

	rulesRegex map[*regexp.Regexp]string

	// The status code when redirecting
	// This is ignored if Redirect is disabled
	// Optional. Default: 302 Temporary Redire


estLogOutputMu sync.Mutex

func withCapturedLogOutput(t *testing.T, writer io.Writer) {
	t.Helper()

	servicesTestLogOutputMu.Lock()
	cleanupRegistered := false
	defer func() {
		if !cleanupRegistered {
			servicesTestLogOutputMu.Unlock()
		}
	}()

	currentOutput := log.DefaultLogger[*stdlog.Logger]().Logger().Writer()
	t.Cleanup(func() {
		log.SetOutput(currentOutput)
		servicesTestLogOutputMu.Unlock()
	})
	cleanupRegistered = true

	log.SetOutput(writer)
}

func (*shutdownHookStorage) GetWithContext(conte

ror {
	return nil
}

func (*shutdownHookStorage) Set(string, []byte, time.Duration) error {
	return nil
}

func (*shutdownHookStorage) DeleteWithContext(context.Context, string) error {
	return nil
}

func (*shutdownHookStorage) Delete(string) error {
	ret

xt.Context, string) ([]byte, error) {
	return nil, nil
}

func (*shutdownHookStorage) Get(string) ([]byte, error) {
	return nil, nil
}

func (*shutdownHookStorage) SetWithContext(context.Context, string, []byte, time.Duration) er


hal
	msgPackEncoder utils.MsgPackMarshal
	msgPackDecoder utils.MsgPackUnmarshal
	cborEncoder    utils.CBORMarshal
	cborDecoder    utils.CBORUnmarshal
	xmlEncoder     utils.XMLMarshal
	xmlDecoder     utils.XMLUnmarshal
	prefix         string
}

func newSharedState(cfg *Config) *SharedState {
	if cfg == nil {
		cfg = &Config{}
	}

	prefix := cfg.SharedStatePrefix
	if prefix == "" {
		prefix = defaultSharedStatePrefix
		if cfg.AppName != "" {
			prefix += cfg.AppName + "-"
		}
	}

	jsonEncoder := cfg.JSONEncod

al
	}
	xmlDecoder := cfg.XMLDecoder
	if xmlDecoder == nil {
		xmlDecoder = xml.Unmarshal
	}

	return &SharedState{
		storage:        cfg.SharedStorage,
		jsonEncoder:    jsonEncoder,
		jsonDecoder:    jsonDecoder,
		msgPackEncoder: cfg.MsgPackEncoder,
		ms

er
	if jsonEncoder == nil {
		jsonEncoder = json.Marshal
	}
	jsonDecoder := cfg.JSONDecoder
	if jsonDecoder == nil {
		jsonDecoder = json.Unmarshal
	}
	xmlEncoder := cfg.XMLEncoder
	if xmlEncoder == nil {
		xmlEncoder = xml.Marsh


 a thread-safe implementation of a map[string]any, using sync.Map.
type State struct {
	dependencies  sync.Map
	servicePrefix string
}

// NewState creates a new instance of State.
func newState() *State {
	// Initialize the services state prefix using a hashed random string
	return &State{
		dependencies:  sync.Map{},
		servicePrefix: servicesStatePrefixHash,
	}
}

// Set sets a key-value pair in the State.
func (s *State) Set(key string, value any) {
	s.dependencies.Store(key, value)
}

// Get retrieves a

f dep, ok := s.Get(key); ok {
		return dep
	}

	panic("state: dependency not found!")
}

// Has checks if a key is present in the State.
// It returns a boolean indicating if the key is present.
func (s *State) Has(key string) bool {
	_, ok := s.Get(key)

 value from the State.
func (s *State) Get(key string) (any, bool) {
	return s.dependencies.Load(key)
}

// MustGet retrieves a value from the State and panics if the key is not found.
func (s *State) MustGet(key string) any {
	i


"context"
	"time"
)

// Storage interface for communicating with different database/key-value
// providers
type Storage interface {
	// GetWithContext gets the value for the given key with a context.
	// `nil, nil` is returned when the key does not exist
	GetWithContext(ctx context.Context, key string) ([]byte, error)

	// Get gets the value for the given key.
	// `nil, nil` is returned when the key does not exist
	Get(key string) ([]byte, error)

	// SetWithContext stores the given value for the given key

or the given key along
	// with an expiration value, 0 means no expiration.
	// Empty key or value will be ignored without an error.
	Set(key string, val []byte, exp time.Duration) error

	// DeleteWithContext deletes the value for the given key with a con

	// with an expiration value, 0 means no expiration.
	// Empty key or value will be ignored without an error.
	SetWithContext(ctx context.Context, key string, val []byte, exp time.Duration) error

	// Set stores the given value f


	"github.com/gofiber/fiber/v3"
	"github.com/stretchr/testify/require"
)

func Test_EnvVarStructWithExportVars(t *testing.T) {
	t.Setenv("testKey", "testEnvValue")
	t.Setenv("anotherEnvKey", "anotherEnvVal")
	vars := newEnvVar(Config{
		ExportVars: map[string]string{"testKey": "", "testDefaultKey": "testDefaultVal"},
	})

	require.Equal(t, "testEnvValue", vars.Vars["testKey"])
	require.Equal(t, "testDefaultVal", vars.Vars["testDefaultKey"])
	require.Empty(t, vars.Vars["anotherEnvKey"])
}

func Test_EnvVarH

ror(t, err)

	app := fiber.New()
	app.Use("/envvars", New(Config{
		ExportVars: map[string]string{"testKey": ""},
	}))

	req, err := http.NewRequestWithContext(context.Background(), fiber.MethodGet, "http://localhost/envvars", http.NoBody)
	require.NoError

andler(t *testing.T) {
	t.Setenv("testKey", "testVal")

	expectedEnvVarResponse, err := json.Marshal(
		struct {
			Vars map[string]string `json:"vars"`
		}{
			Vars: map[string]string{"testKey": "testVal"},
		},
	)
	require.NoEr


ar

import (
	"os"

	"github.com/gofiber/fiber/v3"
)

const hAllow = fiber.MethodGet + ", " + fiber.MethodHead

// EnvVar captures environment variables that are exposed through the
// middleware response.
type EnvVar struct {
	Vars map[string]string `json:"vars"`
}

func (envVar *EnvVar) set(key, val string) {
	envVar.Vars[key] = val
}

// New creates a handler that returns configured environment variables as a
// JSON response.
func New(config ...Config) fiber.Handler {
	cfg := configDefault(config...)

Byte, err := c.App().Config().JSONEncoder(envVar)
		if err != nil {
			return c.Status(fiber.StatusInternalServerError).SendString(err.Error())
		}
		c.Set(fiber.HeaderContentType, fiber.MIMEApplicationJSONCharsetUTF8)
		return c.Send(varsByte)
	}
}

func

return func(c fiber.Ctx) error {
		method := c.Method()
		if method != fiber.MethodGet && method != fiber.MethodHead {
			c.Set(fiber.HeaderAllow, hAllow)
			return fiber.ErrMethodNotAllowed
		}

		envVar := newEnvVar(cfg)
		vars


e earlydata

import (
	"github.com/gofiber/fiber/v3"
)

// The contextKey type is unexported to prevent collisions with context keys defined in
// other packages.
type contextKey int

const (
	localsKeyAllowed contextKey = 0 // earlydata_allowed
)

// IsEarly returns true if the request used early data and was accepted by the middleware.
func IsEarly(c fiber.Ctx) bool {
	return c.Locals(localsKeyAllowed) != nil
}

// New creates a new middleware handler
// https://datatracker.ietf.org/doc/html/rfc8470#secti

!= nil && cfg.Next(c) {
			return c.Next()
		}

		// Continue stack if request is not an early-data request
		if !cfg.IsEarlyData(c) {
			return c.Next()
		}

		// Abort if we can't trust the early-data header
		if !c.IsProxyTrusted() {
			return cfg.Error

on-5.1
func New(config ...Config) fiber.Handler {
	// Set default config
	cfg := configDefault(config...)

	// Return new handler
	return func(c fiber.Ctx) error {
		// Don't execute middleware if Next returns true
		if cfg.Next


fiber/v3"
)

// ResponseFormat defines the format of the healthcheck response.
type ResponseFormat int

const (
	// FormatText returns a plain text response (default behavior).
	FormatText ResponseFormat = iota
	// FormatJSON returns a JSON response.
	FormatJSON
	// FormatXML returns an XML response.
	FormatXML
	// FormatMsgPack returns a MessagePack response.
	FormatMsgPack
	// FormatCBOR returns a CBOR response.
	FormatCBOR
)

// Config defines the configuration options for the healthcheck middleware.
typ

ther handlers were defined to return a different status.
	//
	// Optional. Default: nil
	Next func(fiber.Ctx) bool

	// Probe is executed to determine the current health state. It can be used for liveness,
	// readiness or startup checks. Returning true in

e Config struct {
	// Next defines a function to skip this middleware when returned true. If this function returns true
	// and no other handlers are defined for the route, Fiber will return a status 404 Not Found, since
	// no o


MethodGet, path, http.NoBody))
	require.NoError(t, err)
	require.Equal(t, expectedStatus, req.StatusCode, "path: "+path+" should match "+strconv.Itoa(expectedStatus))
}

func shouldGiveOK(t *testing.T, app *fiber.App, path string) {
	t.Helper()
	shouldGiveStatus(t, app, path, fiber.StatusOK)
}

func shouldGiveNotFound(t *testing.T, app *fiber.App, path string) {
	t.Helper()
	shouldGiveStatus(t, app, path, fiber.StatusNotFound)
}

func Test_HealthCheck_Strict_Routing_Default(t *testing.T) {
	t.Parallel()

	a

ouldGiveOK(t, app, "/startupz")
	shouldGiveNotFound(t, app, "/readyz/")
	shouldGiveNotFound(t, app, "/livez/")
	shouldGiveNotFound(t, app, "/startupz/")
	shouldGiveNotFound(t, app, "/notDefined/readyz")
	shouldGiveNotFound(t, app, "/notDefined/livez")
	sho

pp := fiber.New(fiber.Config{
		StrictRouting: true,
	})

	app.Get(LivenessEndpoint, New())
	app.Get(ReadinessEndpoint, New())
	app.Get(StartupEndpoint, New())

	shouldGiveOK(t, app, "/readyz")
	shouldGiveOK(t, app, "/livez")
	sh


(Config{
		Rules: map[string]string{
			"/default": "google.com",
		},
		StatusCode: fiber.StatusMovedPermanently,
	}))
	app.Use(New(Config{
		Rules: map[string]string{
			"/default/*": "fiber.wiki",
		},
		StatusCode: fiber.StatusTemporaryRedirect,
	}))
	app.Use(New(Config{
		Rules: map[string]string{
			"/redirect/*": "$1",
		},
		StatusCode: fiber.StatusSeeOther,
	}))
	app.Use(New(Config{
		Rules: map[string]string{
			"/pattern/*": "golang.org",
		},
		StatusCode: fiber.StatusFound,
	}))

	app.Use(New(C

nently,
	}))

	app.Get("/api/*", func(c fiber.Ctx) error {
		return c.SendString("API")
	})

	app.Get("/new", func(c fiber.Ctx) error {
		return c.SendString("Hello, World!")
	})

	tests := []struct {
		name       string
		url        string
		redirectTo st

onfig{
		Rules: map[string]string{
			"/": "/swagger",
		},
		StatusCode: fiber.StatusMovedPermanently,
	}))
	app.Use(New(Config{
		Rules: map[string]string{
			"/params": "/with_params",
		},
		StatusCode: fiber.StatusMovedPerma


 (
	"github.com/gofiber/fiber/v3"
)

const (
	DefaultHeaderName      = "Early-Data"
	DefaultHeaderTrueValue = "1"
)

// Config defines the config for middleware.
type Config struct {
	// Next defines a function to skip this middleware when returned true.
	//
	// Optional. Default: nil
	Next func(c fiber.Ctx) bool

	// IsEarlyData returns whether the request is an early-data request.
	//
	// Optional. Default: a function which checks if the "Early-Data" request header equals "1".
	IsEarlyData func(c fiber.Ct

owEarlyData func(c fiber.Ctx) bool

	// Error is returned if an early-data request is rejected.
	//
	// Optional. Default: fiber.ErrTooEarly.
	Error error
}

// ConfigDefault is the default config
var ConfigDefault = Config{
	IsEarlyData: func(c fiber.Ctx)

x) bool

	// AllowEarlyData returns whether the early-data request should be allowed or rejected.
	//
	// Optional. Default: a function which rejects the request on unsafe and allows the request on safe HTTP request methods.
	All


const (
	headerName   = "Early-Data"
	headerValOn  = "1"
	headerValOff = "0"
)

const (
	trustedRemoteAddr   = "0.0.0.0:1234"
	untrustedRemoteAddr = "203.0.113.1:1234"
)

func appWithConfig(t *testing.T, c *fiber.Config) *fiber.App {
	t.Helper()

	var app *fiber.App
	if c == nil {
		app = fiber.New()
	} else {
		app = fiber.New(*c)
	}

	app.Use(New())

	// Middleware to test IsEarly func
	const localsKeyTestValid = "earlydata_testvalid"
	app.Use(func(c fiber.Ctx) error {
		isEarly := IsEarly(c)

		switch h

return errors.New("should be early-data on safe HTTP methods")
				}
			default:
				if isEarly {
					return errors.New("early-data unsupported on unsafe HTTP methods")
				}
			}

		default:
			return fmt.Errorf("header has unsupported value: %s", h)
		}

 := c.Get(headerName); h {
		case "", headerValOff:
			if isEarly {
				return errors.New("is early-data even though it's not")
			}

		case headerValOn:
			switch {
			case fiber.IsMethodSafe(c.Method()):
				if !isEarly {


thcheck

import (
	"github.com/gofiber/fiber/v3"
)

// healthResponse represents the JSON/XML/MsgPack/CBOR response structure.
type healthResponse struct {
	Status string `json:"status" xml:"status" msgpack:"status" cbor:"status"`
}

// New returns a health-check handler that responds based on the provided
// configuration.
func New(config ...Config) fiber.Handler {
	cfg := configDefault(config...)

	return func(c fiber.Ctx) error {
		// Don't execute middleware if Next returns true
		if cfg.Next != nil &&

iceUnavailable
			statusMessage = "Service Unavailable"
		}

		// Set the status code
		c.Status(statusCode)

		// Return response based on configured format
		switch cfg.ResponseFormat {
		case FormatJSON:
			return c.JSON(healthResponse{Status: statusMes

cfg.Next(c) {
			return c.Next()
		}

		if c.Method() != fiber.MethodGet {
			return c.Next()
		}

		healthy := cfg.Probe(c)
		statusCode := fiber.StatusOK
		statusMessage := "OK"

		if !healthy {
			statusCode = fiber.StatusServ


e recover //nolint:predeclared // TODO: Rename to some non-builtin

import (
	"fmt"
	"os"
	"runtime/debug"

	"github.com/gofiber/fiber/v3"
)

func defaultStackTraceHandler(_ fiber.Ctx, e any) {
	fmt.Fprintf(os.Stderr, "panic: %v\n\n%s\n", e, debug.Stack())
}

// DefaultPanicHandler returns r directly if it's an error, and creates a new one with the %v verb otherwise.
func DefaultPanicHandler(_ fiber.Ctx, r any) error {
	if err, ok := r.(error); ok {
		return err
	}
	return fmt.Errorf("%v", r)
}

// New crea

er() to overwrite the error
		// Don't execute middleware if Next returns true
		if cfg.Next != nil && cfg.Next(c) {
			return c.Next()
		}

		// Catch panics
		defer func() {
			if r := recover(); r != nil {
				if cfg.EnableStackTrace {
					cfg.StackTra

tes a new middleware handler
func New(config ...Config) fiber.Handler {
	// Set default config
	cfg := configDefault(config...)

	// Return new handler
	return func(c fiber.Ctx) (err error) { //nolint:nonamedreturns // Uses recov


import (
	"regexp"

	"github.com/gofiber/fiber/v3"
)

// Config defines the config for middleware.
type Config struct {
	// Next defines a function to skip middleware.
	// Optional. Default: nil
	Next func(fiber.Ctx) bool

	// Rules defines the URL path rewrite rules. The values captured in asterisk can be
	// retrieved by index e.g. $1, $2 and so on.
	// Required. Example:
	// "/old":              "/new",
	// "/api/*":            "/$1",
	// "/js/*":             "/public/javascript/$1",
	// "/users/*/orders

	rulesRegex map[*regexp.Regexp]string
}

// Helper function to set default values
func configDefault(config ...Config) Config {
	// Return default config if nothing provided
	if len(config) < 1 {
		return Config{}
	}

	// Override default config
	cfg := co

/*": "/user/$1/order/$2",
	Rules map[string]string


,
	})

	if m == nil {
		t.Error("Expected middleware to be returned, got nil")
	}

	// Test with full config
	m = New(Config{
		Next: func(fiber.Ctx) bool {
			return true
		},
		Rules: map[string]string{
			"/old": "/new",
		},
	})

	if m == nil {
		t.Error("Expected middleware to be returned, got nil")
	}
}

func Test_Rewrite(t *testing.T) {
	// Case 1: Next function always returns true
	app := fiber.New()
	app.Use(New(Config{
		Next: func(fiber.Ctx) bool {
			return true
		},
		Rules: map[string]string{

e.NoError(t, err)
	resp, err := app.Test(req)
	require.NoError(t, err)
	body, err := io.ReadAll(resp.Body)
	require.NoError(t, err)
	bodyString := string(body)

	require.NoError(t, err)
	require.Equal(t, fiber.StatusOK, resp.StatusCode)
	require.Equal(t, "

			"/old": "/new",
		},
	}))

	app.Get("/old", func(c fiber.Ctx) error {
		return c.SendString("Rewrite Successful")
	})

	req, err := http.NewRequestWithContext(context.Background(), fiber.MethodGet, "/old", http.NoBody)
	requir


// RFC 1035 length limits.
const (
	maxDomainLength = 253
	maxLabelLength  = 63
)

type parsedHosts struct {
	exact            map[string]struct{}
	wildcardSuffixes []string
}

// parseAllowedHosts splits AllowedHosts into exact and wildcard groups,
// normalizing entries (port strip, lowercase, IDN→Punycode) and enforcing
// RFC 1035 length limits. Panics on misconfiguration so it surfaces at startup.
func parseAllowedHosts(hosts []string) parsedHosts {
	parsed := parsedHosts{
		exact: make(map[string]stru

"hostauthorization: invalid host " + h + " — subdomain wildcards use the \"*.example.com\" form")
		}

		isWildcard := strings.HasPrefix(h, "*.")
		if isWildcard {
			h = h[2:]
		}

		h = normalizeHost(h)
		if h == "" {
			continue
		}

		validateHostLengt

ct{}, len(hosts)),
	}

	for _, h := range hosts {
		h = utils.TrimSpace(h)
		if h == "" {
			continue
		}

		// Reject the leading-dot form some other tools use; we want "*.example.com".
		if len(h) > 1 && h[0] == '.' {
			panic(


thub.com/gofiber/fiber/v3"
	"github.com/valyala/fasthttp"
)

// Config defines the config for middleware.
type Config struct {
	// Next defines a function to skip this middleware when returned true.
	//
	// Optional. Default: nil
	Next func(c fiber.Ctx) bool

	// ModifyRequest allows you to alter the request
	//
	// Optional. Default: nil
	ModifyRequest fiber.Handler

	// ModifyResponse allows you to alter the response
	//
	// Optional. Default: nil
	ModifyResponse fiber.Handler

	// tls config for the http

	Client *fasthttp.LBClient

	// Servers defines a list of <scheme>://<host> HTTP servers,
	//
	// which are used in a round-robin manner.
	// i.e.: "https://foobar.com, http://www.foobar.com"
	//
	// Required
	Servers []string

	// Timeout is the request t

 client.
	TLSConfig *tls.Config

	// Client is custom client when client config is complex.
	// Note that Servers, Timeout, WriteBufferSize, ReadBufferSize, TLSConfig
	// and DialDualStack will not be used if the client are set.


ad balancer among multiple upstream servers
func Balancer(config ...Config) fiber.Handler {
	// Set default config
	cfg := configDefault(config...)

	// Load balanced client
	lbc := &fasthttp.LBClient{}
	// Note that Servers, Timeout, WriteBufferSize, ReadBufferSize and TLSConfig
	// will not be used if the client are set.
	if cfg.Client == nil {
		// Set timeout
		lbc.Timeout = cfg.Timeout
		// Scheme must be provided, falls back to http
		for _, server := range cfg.Servers {
			if !strings.HasPrefix(serve

				Addr:                     u.Host,
				MaxConns:                 cfg.MaxConnsPerHost,

				ReadBufferSize:  cfg.ReadBufferSize,
				WriteBufferSize: cfg.WriteBufferSize,

				TLSConfig: cfg.TLSConfig,

				DialDualStack: cfg.DialDualStack,
			}

			lbc.

r, "http") {
				server = "http://" + server
			}

			u, err := url.Parse(server)
			if err != nil {
				panic(err)
			}

			client := &fasthttp.HostClient{
				NoDefaultUserAgentHeader: true,
				DisablePathNormalizing:   true,


e to some non-builtin

import (
	"errors"
	"fmt"
	"net/http"
	"net/http/httptest"
	"testing"

	"github.com/gofiber/fiber/v3"
	"github.com/stretchr/testify/require"
)

// go test -run Test_Recover
func Test_Recover(t *testing.T) {
	t.Parallel()

	tests := []struct {
		name         string
		panicVal     any
		panicHandler func(c fiber.Ctx, r any) error
		errorMsg     string
	}{
		{
			name:         "non-error panic will be handled by default",
			panicVal:     "Hi, I'm an error!",
			panicHandler: nil,
			err

{
			name:     "non-error panic will be handled",
			panicVal: "Hi, I'm an error!",
			panicHandler: func(c fiber.Ctx, r any) error {
				return fmt.Errorf("[RECOVERED]: %w", DefaultPanicHandler(c, r))
			},
			errorMsg: "[RECOVERED]: Hi, I'm an error!",

orMsg:     "Hi, I'm an error!",
		},
		{
			name:         "error panic will be handled by default",
			panicVal:     errors.New("hi, I'm an error object"),
			panicHandler: nil,
			errorMsg:     "hi, I'm an error object",
		},


e rewrite

import (
	"regexp"
	"strconv"
	"strings"

	"github.com/gofiber/fiber/v3"
)

// New creates a new middleware handler
func New(config ...Config) fiber.Handler {
	cfg := configDefault(config...)

	// Initialize
	cfg.rulesRegex = map[*regexp.Regexp]string{}
	for k, v := range cfg.Rules {
		k = strings.ReplaceAll(k, "*", "(.*)")
		k += "$"
		cfg.rulesRegex[regexp.MustCompile(k)] = v
	}
	// Middleware function
	return func(c fiber.Ctx) error {
		// Next request to skip middleware
		if cfg.Next != nil &

// https://github.com/labstack/echo/blob/master/middleware/rewrite.go
func captureTokens(pattern *regexp.Regexp, input string) *strings.Replacer {
	groups := pattern.FindAllStringSubmatch(input, -1)
	if groups == nil {
		return nil
	}
	values := groups[0]

& cfg.Next(c) {
			return c.Next()
		}
		// Rewrite
		for k, v := range cfg.rulesRegex {
			replacer := captureTokens(k, c.Path())
			if replacer != nil {
				c.Path(replacer.Replace(v))
				break
			}
		}
		return c.Next()
	}
}


rr := net.Listen(network, address)
	require.NoError(t, err)

	addr = ln.Addr().String()

	startServer(target, ln)

	return target, addr
}

func createProxyTestServerIPv4(t *testing.T, handler fiber.Handler) (target *fiber.App, addr string) { //nolint:nonamedreturns // gocritic unnamedResult prefers naming returned target app and address for readability
	t.Helper()
	return createProxyTestServer(t, handler, fiber.NetworkTCP4, "127.0.0.1:0")
}

func createProxyTestServerIPv6(t *testing.T, handler fiber.Handler

:0")
}

func createRedirectServer(t *testing.T) string {
	t.Helper()
	app := fiber.New()

	var addr string
	app.Get("/", func(c fiber.Ctx) error {
		c.Location("http://" + addr + "/final")
		return c.Status(fiber.StatusMovedPermanently).SendString("redirec

) (target *fiber.App, addr string) { //nolint:nonamedreturns // gocritic unnamedResult prefers naming returned target app and address for readability
	t.Helper()
	return createProxyTestServer(t, handler, fiber.NetworkTCP6, "[::1]


edHostsFuncOnly(t *testing.T) {
	t.Parallel()

	cfg := configDefault(Config{
		AllowedHostsFunc: func(host string) bool {
			return host == "example.com"
		},
	})
	require.NotNil(t, cfg.AllowedHostsFunc)
}

func Test_ConfigPanicHostExceedsRFC1035TotalLength(t *testing.T) {
	t.Parallel()

	tooLong := strings.Repeat("a", 254)
	require.Panics(t, func() {
		New(Config{
			AllowedHosts: []string{tooLong},
		})
	})
}

func Test_ConfigPanicLeadingDotForm(t *testing.T) {
	t.Parallel()

	require.Panics(t, func() {

w(Config{
			AllowedHosts: []string{tooLong},
		})
	})
}

func Test_ConfigCustomErrorHandler(t *testing.T) {
	t.Parallel()

	custom := func(c fiber.Ctx, _ error) error {
		return c.Status(fiber.StatusTeapot).SendString("nope")
	}

	cfg := configDefault(Con

	New(Config{
			AllowedHosts: []string{".myapp.com"},
		})
	})
}

func Test_ConfigPanicLabelExceedsRFC1035Length(t *testing.T) {
	t.Parallel()

	tooLong := strings.Repeat("a", 64) + ".example.com"
	require.Panics(t, func() {
		Ne


import (
	"errors"

	"github.com/gofiber/fiber/v3"
)

// ErrForbiddenHost is returned when the Host header does not match any allowed host.
var ErrForbiddenHost = errors.New("hostauthorization: forbidden host")

// Config defines the config for the host authorization middleware.
type Config struct {
	// Next defines a function to skip this middleware when returned true.
	// Use this to exclude health check endpoints or other paths from host validation.
	//
	// Optional. Default: nil
	Next func(c fiber.Ctx

n true to allow.
	//
	// Optional. Default: nil
	AllowedHostsFunc func(host string) bool

	// ErrorHandler is called when a request is rejected.
	// Receives ErrForbiddenHost as the error.
	//
	// Optional. Default: returns 403 Forbidden.
	ErrorHandler fib

) bool

	// AllowedHostsFunc is a dynamic validator called only when no static
	// AllowedHosts rule matches. Receives the normalized hostname: port stripped,
	// trailing dot removed, IPv6 brackets removed, lowercased.
	// Retur


= "no-store"
	privateDirective = "private"
)

type requestCacheDirectives struct {
	maxAge   uint64
	maxStale uint64
	minFresh uint64

	maxAgeSet    bool
	maxStaleSet  bool
	maxStaleAny  bool
	minFreshSet  bool
	noStore      bool
	noCache      bool
	onlyIfCached bool
}

var ignoreHeaders = map[string]struct{}{
	"Age":                 {},
	"Cache-Control":       {}, // already stored explicitly by the cache manager
	"Connection":          {},
	"Content-Encoding":    {}, // already stored explicitly by the ca

ready stored explicitly by the cache manager
	"Keep-Alive":          {},
	"Proxy-Authenticate":  {},
	"Proxy-Authorization": {},
	"TE":                  {},
	"Trailers":            {},
	"Transfer-Encoding":   {},
	"Upgrade":             {},
}

var cacheabl

che manager
	"Content-Type":        {}, // already stored explicitly by the cache manager
	"Date":                {},
	"ETag":                {}, // already stored explicitly by the cache manager
	"Expires":             {}, // al


responsetime

import (
	"github.com/gofiber/fiber/v3"
)

// Config defines the config for middleware.
type Config struct {
	// Next defines a function to skip this middleware when returned true.
	//
	// Optional. Default: nil
	Next func(c fiber.Ctx) bool

	// Header is the header key used to set the response time.
	//
	// Optional. Default: "X-Response-Time"
	Header string
}

// ConfigDefault is the default config.
var ConfigDefault = Config{
	Next:   nil,
	Header: fiber.HeaderXResponseTime,
}

// Helper fu

fig ...Config) Config {
	// Return default config if nothing provided
	if len(config) < 1 {
		return ConfigDefault
	}

	// Override default config
	cfg := config[0]

	// Set default values
	if cfg.Header == "" {
		cfg.Header = ConfigDefault.Header
	}

	ret

nction to set default values.
func configDefault(con


port (
	"github.com/gofiber/fiber/v3"
)

// Config defines the config for middleware.
type Config struct {
	// Next defines a function to skip this middleware when returned true.
	//
	// Optional. Default: nil
	Next func(c fiber.Ctx) bool

	// Prefix defines a URL prefix added before "/debug/pprof".
	// Note that it should start with (but not end with) a slash.
	// Example: "/federated-fiber"
	//
	// Optional. Default: ""
	Prefix string
}

var ConfigDefault = Config{
	Next:   nil,
	Prefix: "",
}

func confi

lt config if nothing provided
	if len(config) < 1 {
		return ConfigDefault
	}

	// Override default config
	cfg := config[0]

	// Set default values
	if cfg.Next == nil {
		cfg.Next = ConfigDefault.Next
	}
	if cfg.Prefix == "" {
		cfg.Prefix = ConfigDefaul

gDefault(config ...Config) Config {
	// Return defau


kenName: "access_token",
			description:   "auth with wrong key",
			APIKey:        "WRONGKEY",
			expectedCode:  401,
			expectedBody:  ErrMissingOrMalformedAPIKey.Error(),
		},
	}

	for _, authSource := range testSources {
		t.Run(authSource, func(t *testing.T) {
			for _, test := range tests {
				app := fiber.New(fiber.Config{UnescapePath: true})

				testKey := test.APIKey
				correctKey := CorrectKey

				// Use a simple key for param and cookie to avoid encoding issues in the test setup
				if authSo

g{
					Extractor: func() extractors.Extractor {
						switch authSource {
						case headerExtractorName:
							return extractors.FromHeader(test.authTokenName)
						case authHeaderExtractorName:
							return extractors.FromAuthHeader("Bearer")
						c

urce == paramExtractorName || authSource == cookieExtractorName {
					if test.APIKey != "" && test.APIKey != "WRONGKEY" {
						testKey = "simple-key"
						correctKey = "simple-key"
					}
				}

				authMiddleware := New(Confi


pto/cipher"
	"crypto/rand"
	"encoding/base64"
	"errors"
	"fmt"
	"slices"
)

var (
	ErrInvalidKeyLength      = errors.New("encryption key must be 16, 24, or 32 bytes")
	ErrInvalidEncryptedValue = errors.New("encrypted value is not valid")
)

// decodeKey decodes the provided base64-encoded key and validates its length.
// It returns the decoded key bytes or an error when invalid.
func decodeKey(key string) ([]byte, error) {
	keyDecoded, err := base64.StdEncoding.DecodeString(key)
	if err != nil {
		return ni

 provided base64-encoded key is of valid length.
func validateKey(key string) error {
	_, err := decodeKey(key)
	return err
}

// EncryptCookie Encrypts a cookie value with specific encryption key
func EncryptCookie(name, value, key string) (string, error)

l, fmt.Errorf("failed to base64-decode key: %w", err)
	}

	keyLen := len(keyDecoded)
	if keyLen != 16 && keyLen != 24 && keyLen != 32 {
		return nil, ErrInvalidKeyLength
	}

	return keyDecoded, nil
}

// validateKey checks if the


OT trigger a request timeout.
	errUnrelated = errors.New("unmatched error")
)

// sleepWithContext simulates a task that takes `d` time, but returns `te` if the context is canceled.
func sleepWithContext(ctx context.Context, d time.Duration, te error) error {
	timer := time.NewTimer(d)
	defer timer.Stop() // Clean up the timer

	select {
	case <-ctx.Done():
		return te
	case <-timer.C:
		return nil
	}
}

// TestTimeout_Success tests a handler that completes within the allotted timeout.
func TestTimeout_Succ

ithContext(c.Context(), 10*time.Millisecond, context.DeadlineExceeded); err != nil {
			return err
		}
		return c.SendString("OK")
	}, Config{Timeout: 50 * time.Millisecond}))

	req := httptest.NewRequest(fiber.MethodGet, "/fast", http.NoBody)
	resp, err :

ess(t *testing.T) {
	t.Parallel()
	app := fiber.New()

	// Our middleware wraps a handler that sleeps for 10ms, well under the 50ms limit.
	app.Get("/fast", New(func(c fiber.Ctx) error {
		// Simulate some work
		if err := sleepW


ed (but with hashed key due to param limit)
	resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, url, http.NoBody))
	require.NoError(t, err)
	require.Equal(t, fiber.StatusOK, resp.StatusCode)
	require.Equal(t, cacheMiss, resp.Header.Get("X-Cache"))
	require.Equal(t, 1, count)

	// Second request should hit cache
	resp, err = app.Test(httptest.NewRequest(fiber.MethodGet, url, http.NoBody))
	require.NoError(t, err)
	require.Equal(t, fiber.StatusOK, resp.StatusCode)
	require.Equal(t, cacheHit, resp.Head

ssiveQueryBuffer(t *testing.T) {
	t.Parallel()

	app := fiber.New(fiber.Config{
		ReadBufferSize: 16384, // Increase buffer to accommodate large query strings for testing
	})
	app.Use(New(Config{Expiration: 1 * time.Hour}))

	var count int
	app.Get("/", fu

er.Get("X-Cache"))
	require.Equal(t, 1, count, "Handler should not be called on cache hit")
}

// Test_Cache_Security_DoS_ExcessiveQueryBuffer tests protection against DoS via query buffer growth
func Test_Cache_Security_DoS_Exce


r
			return c.Status(fiber.StatusInternalServerError).SendString("storage failure")
		},
	})

	app.Use(New(Config{Storage: storage, Expiration: time.Second}))
	app.Get("/", func(c fiber.Ctx) error {
		return c.SendString("ok")
	})

	resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", http.NoBody))
	require.NoError(t, err)
	require.Equal(t, fiber.StatusInternalServerError, resp.StatusCode)
	require.Error(t, captured)
	require.ErrorContains(t, captured, "cache: failed to store raw key")
}

func Te

without relying on time-based conversions
	expired := &item{exp: 1}
	raw, err := expired.MarshalMsg(nil)
	require.NoError(t, err)

	storage.data["GET|/|q=|h=accept:|accept-encoding:|accept-language:"] = raw

	var captured error
	app := fiber.New(fiber.Conf

stCacheStorageDeleteError(t *testing.T) {
	t.Parallel()

	storage := newFailingCacheStorage()
	storage.errs["del|GET|/|q=|h=accept:|accept-encoding:|accept-language:"] = errors.New("boom")

	// Use an obviously expired timestamp


ype Config struct {
	// Storage is used to store the state of the middleware
	//
	// Default: an in-memory store for this process only
	Storage fiber.Storage

	// Next defines a function to skip this middleware when returned true.
	//
	// Optional. Default: nil
	Next func(c fiber.Ctx) bool

	// CacheInvalidator defines a function to invalidate the cache when returned true
	//
	// Optional. Default: nil
	CacheInvalidator func(fiber.Ctx) bool

	// KeyGenerator allows you to generate custom keys.
	//
	// When

  - Selected cookies (from KeyCookies)
	//
	// The resulting cache key is always partitioned by request method internally.
	//
	// Default: nil
	KeyGenerator func(fiber.Ctx) string

	// ExpirationGenerator allows you to generate a custom expiration per req

nil, the middleware uses a structured key based on:
	//   - Request path (bounded to 192 bytes, hashed if longer)
	//   - Canonical query string (sorted parameters, bounded)
	//   - Selected request headers (from KeyHeaders)
	//


=true -unexported
// Default slice limits are sized for cache payloads, with tighter field caps below.
//
//go:generate msgp -o=manager_msgp.go -tests=true -unexported
//nolint:revive // msgp requires tags on unexported fields for limit enforcement.
type item struct {
	headers         []cachedHeader `msg:",limit=1024"` // Typical HTTP header count stays well below this.
	body            []byte         // Cache bodies are bounded by storage policy, not msgp limits.
	ctype           []byte         `msg:",limi

es are bounded.
	expires         []byte         `msg:",limit=128"`  // Expires is a short HTTP-date string.
	etag            []byte         `msg:",limit=256"`  // ETags are small tokens/quoted strings.
	date            uint64
	status          int
	age

t=256"`  // Content-Type values are short per RFCs.
	cencoding       []byte         `msg:",limit=128"`  // Content-Encoding is typically a short token.
	cacheControl    []byte         `msg:",limit=2048"` // Cache-Control directiv


	"github.com/tinylib/msgp/msgp"
)

func TestMarshalUnmarshalcachedHeader(t *testing.T) {
	v := cachedHeader{}
	bts, err := v.MarshalMsg(nil)
	if err != nil {
		t.Fatal(err)
	}
	left, err := v.UnmarshalMsg(bts)
	if err != nil {
		t.Fatal(err)
	}
	if len(left) > 0 {
		t.Errorf("%d bytes left over after UnmarshalMsg(): %q", len(left), left)
	}

	left, err = msgp.Skip(bts)
	if err != nil {
		t.Fatal(err)
	}
	if len(left) > 0 {
		t.Errorf("%d bytes left over after Skip(): %q", len(left), left)
	}
}

func Bench

 := make([]byte, 0, v.Msgsize())
	bts, _ = v.MarshalMsg(bts[0:0])
	b.SetBytes(int64(len(bts)))
	b.ReportAllocs()
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		bts, _ = v.MarshalMsg(bts[0:0])
	}
}

func BenchmarkUnmarshalcachedHeader(b *testing.B) {
	v := c

markMarshalMsgcachedHeader(b *testing.B) {
	v := cachedHeader{}
	b.ReportAllocs()
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		v.MarshalMsg(nil)
	}
}

func BenchmarkAppendMsgcachedHeader(b *testing.B) {
	v := cachedHeader{}
	bts


e etag

import (
	"github.com/gofiber/fiber/v3"
)

// Config defines the config for middleware.
type Config struct {
	// Next defines a function to skip this middleware when returned true.
	//
	// Optional. Default: nil
	Next func(c fiber.Ctx) bool
	// Weak indicates that a weak validator is used. Weak etags are easy
	// to generate, but are far less useful for comparisons. Strong
	// validators are ideal for comparisons but can be very difficult
	// to generate efficiently. Weak ETag values of two represen

ill be cached.
	Weak bool
}

// ConfigDefault is the default config
var ConfigDefault = Config{
	Weak: false,
	Next: nil,
}

// Helper function to set default values
func configDefault(config ...Config) Config {
	// Return default config if nothing provide

tations
	// of the same resources might be semantically equivalent, but not
	// byte-for-byte identical. This means weak etags prevent caching
	// when byte range requests are used, but strong etags mean range
	// requests can st


est_ETag_Next
func Test_ETag_Next(t *testing.T) {
	t.Parallel()
	app := fiber.New()
	app.Use(New(Config{
		Next: func(_ fiber.Ctx) bool {
			return true
		},
	}))

	resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", http.NoBody))
	require.NoError(t, err)
	require.Equal(t, fiber.StatusNotFound, resp.StatusCode)
}

// go test -run Test_ETag_SkipError
func Test_ETag_SkipError(t *testing.T) {
	t.Parallel()
	app := fiber.New()

	app.Use(New())

	app.Get("/", func(_ fiber.Ctx) error {
		return fiber.

t_ETag_NotStatusOK(t *testing.T) {
	t.Parallel()
	app := fiber.New()

	app.Use(New())

	app.Get("/", func(c fiber.Ctx) error {
		return c.SendStatus(fiber.StatusCreated)
	})

	resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", http.NoBody))
	r

ErrForbidden
	})

	resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", http.NoBody))
	require.NoError(t, err)
	require.Equal(t, fiber.StatusForbidden, resp.StatusCode)
}

// go test -run Test_ETag_NotStatusOK
func Tes


ofiber/fiber/v3"
	"github.com/gofiber/fiber/v3/middleware/logger"
	"github.com/gofiber/utils/v2"
)

// The contextKey type is unexported to prevent collisions with context keys defined in
// other packages.
type contextKey int

// The keys for the values in context
const (
	requestIDKey contextKey = iota
)

var registerLogContextTagsOnce sync.Once

// New creates a new middleware handler
func New(config ...Config) fiber.Handler {
	registerLogContextTagsOnce.Do(registerLogContextTags)

	// Set default config

D(c.Get(cfg.Header), cfg.Generator)

		// Set new id to response header
		c.Set(cfg.Header, rid)

		// Add the request ID to locals
		fiber.StoreInContext(c, requestIDKey, rid)

		// Continue stack
		return c.Next()
	}
}

func registerLogContextTags() {
	l

	cfg := configDefault(config...)

	// Return new handler
	return func(c fiber.Ctx) error {
		// Don't execute middleware if Next returns true
		if cfg.Next != nil && cfg.Next(c) {
			return c.Next()
		}
		rid := sanitizeRequestI


og"
	"github.com/gofiber/fiber/v3/middleware/logger"
	"github.com/stretchr/testify/require"
)

// go test -run Test_RequestID
func Test_RequestID(t *testing.T) {
	t.Parallel()
	app := fiber.New()

	app.Use(New())

	app.Get("/", func(c fiber.Ctx) error {
		return c.SendString("Hello, World 👋!")
	})

	resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", http.NoBody))
	require.NoError(t, err)
	require.Equal(t, fiber.StatusOK, resp.StatusCode)

	reqid := resp.Header.Get(fiber.HeaderXRequestID)
	requi

sCode)
	require.Equal(t, reqid, resp.Header.Get(fiber.HeaderXRequestID))
}

func Test_RequestID_InvalidHeaderValue(t *testing.T) {
	t.Parallel()

	rid := sanitizeRequestID("bad\r\nid", func() string {
		return "clean-generated-id"
	})

	require.Equal(t, "c

re.Len(t, reqid, 43)

	req := httptest.NewRequest(fiber.MethodGet, "/", http.NoBody)
	req.Header.Add(fiber.HeaderXRequestID, reqid)

	resp, err = app.Test(req)
	require.NoError(t, err)
	require.Equal(t, fiber.StatusOK, resp.Statu


			z.value = []byte{}
			}
			if err != nil {
				err = msgp.WrapError(err, "value")
				return
			}
		default:
			err = dc.Skip()
			if err != nil {
				err = msgp.WrapError(err)
				return
			}
		}
	}
	return
}

// EncodeMsg implements msgp.Encodable
func (z *cachedHeader) EncodeMsg(en *msgp.Writer) (err error) {
	// map header, size 2
	// write "key"
	err = en.Append(0x82, 0xa3, 0x6b, 0x65, 0x79)
	if err != nil {
		return
	}
	err = en.WriteBytes(z.key)
	if err != nil {
		err = msgp.WrapError(err, "key")

Msg implements msgp.Marshaler
func (z *cachedHeader) MarshalMsg(b []byte) (o []byte, err error) {
	o = msgp.Require(b, z.Msgsize())
	// map header, size 2
	// string "key"
	o = append(o, 0x82, 0xa3, 0x6b, 0x65, 0x79)
	o = msgp.AppendBytes(o, z.key)
	// str

		return
	}
	// write "value"
	err = en.Append(0xa5, 0x76, 0x61, 0x6c, 0x75, 0x65)
	if err != nil {
		return
	}
	err = en.WriteBytes(z.value)
	if err != nil {
		err = msgp.WrapError(err, "value")
		return
	}
	return
}

// Marshal


h"
	"slices"

	"github.com/gofiber/fiber/v3"
	"github.com/valyala/bytebufferpool"
)

var (
	weakPrefix = []byte("W/")
	crc32q     = crc32.MakeTable(0xD5828281)
)

// Generate returns a strong ETag for body.
func Generate(body []byte) []byte {
	if uint64(len(body)) > uint64(math.MaxUint32) {
		return nil
	}
	bb := bytebufferpool.Get()
	defer bytebufferpool.Put(bb)
	b := bb.B[:0]
	b = append(b, '"')
	b = appendUint(b, uint32(len(body))) // #nosec G115 -- length checked above
	b = append(b, '-')
	b = appendUin

rn append(weakPrefix, tag...)
}

// New creates a new middleware handler
func New(config ...Config) fiber.Handler {
	// Set default config
	cfg := configDefault(config...)

	normalizedHeaderETag := []byte("Etag")

	// Return new handler
	return func(c fibe

t(b, crc32.Checksum(body, crc32q))
	b = append(b, '"')
	return slices.Clone(b)
}

// GenerateWeak returns a weak ETag for body.
func GenerateWeak(body []byte) []byte {
	tag := Generate(body)
	if tag == nil {
		return nil
	}
	retu


eapEntry struct {
	key   string
	exp   uint64
	bytes uint
	idx   int
}

// indexedHeap is a regular min-heap that allows finding
// elements in constant time. It does so by handing out special indices
// and tracking entry movement.
//
// indexedHeap is used for quickly finding entries with the lowest
// expiration timestamp and deleting arbitrary entries.
type indexedHeap struct {
	// Slice the heap is built on
	entries []heapEntry
	// Mapping "index" to position in heap slice
	indices []int
	// Max index

ion time.
func (h indexedHeap) Less(i, j int) bool {
	return h.entries[i].exp < h.entries[j].exp
}

// Swap implements heap.Interface and swaps the entries at the provided indices.
func (h indexedHeap) Swap(i, j int) {
	h.entries[i], h.entries[j] = h.entri

handed out
	maxidx int
}

// Len implements heap.Interface by reporting the number of entries in the heap.
func (h indexedHeap) Len() int {
	return len(h.entries)
}

// Less implements heap.Interface and orders entries by expirat


e requestid

import (
	"github.com/gofiber/fiber/v3"
	"github.com/gofiber/utils/v2"
)

// Config defines the config for middleware.
type Config struct {
	// Next defines a function to skip this middleware when returned true.
	//
	// Optional. Default: nil
	Next func(c fiber.Ctx) bool

	// Generator defines a function to generate the unique identifier.
	//
	// Optional. Default: utils.SecureToken
	Generator func() string

	// Header is the header key where to get/set the unique request ID
	//
	// Optional. D

	Generator: utils.SecureToken,
}

// Helper function to set default values
func configDefault(config ...Config) Config {
	// Return default config if nothing provided
	if len(config) < 1 {
		return ConfigDefault
	}

	// Override default config
	cfg := con

efault: "X-Request-ID"
	Header string
}

// ConfigDefault is the default config
// It uses a secure token generator for better privacy and security.
var ConfigDefault = Config{
	Next:      nil,
	Header:    fiber.HeaderXRequestID,


kage cache

import (
	"context"
	"testing"
	"time"

	"github.com/gofiber/utils/v2"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

func Test_manager_get(t *testing.T) {
	t.Parallel()
	cacheManager := newManager(nil, true)
	t.Run("Item not found in cache", func(t *testing.T) {
		t.Parallel()
		it, err := cacheManager.get(context.Background(), utils.UUIDv4())
		require.ErrorIs(t, err, errCacheMiss)
		assert.Nil(t, it)
	})
	t.Run("Item found in cache", func(t *testing.T) {
		t.P

et(context.Background(), id)
		require.NoError(t, err)
		assert.NotNil(t, it)
	})
}

func Test_manager_logKey(t *testing.T) {
	t.Parallel()

	redactedManager := newManager(nil, true)
	assert.Equal(t, redactedKey, redactedManager.logKey("secret"))

	plainMa

arallel()
		id := utils.UUIDv4()
		cacheItem := cacheManager.acquire()
		cacheItem.body = []byte("test-body")
		require.NoError(t, cacheManager.set(context.Background(), id, cacheItem, 10*time.Second))
		it, err := cacheManager.g


"
	"net/http/httptest"
	"testing"
	"time"

	"github.com/gofiber/fiber/v3"
	"github.com/stretchr/testify/require"
)

func TestResponseTimeMiddleware(t *testing.T) {
	t.Parallel()

	boom := errors.New("boom")

	tests := []struct {
		name                  string
		expectedStatus        int
		useCustomErrorHandler bool
		returnError           bool
		expectHeader          bool
		skipWithNext          bool
	}{
		{
			name:           "sets duration header",
			expectedStatus: fiber.StatusOK,
			expectHeader:   tru

  fiber.StatusTeapot,
			useCustomErrorHandler: true,
			returnError:           true,
			expectHeader:          true,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			t.Parallel()

			configs := []Config(nil)
			if tt.skipWithN

e,
		},
		{
			name:           "skips when Next returns true",
			expectedStatus: fiber.StatusOK,
			expectHeader:   false,
			skipWithNext:   true,
		},
		{
			name:                  "propagates errors",
			expectedStatus:


	"testing"
	"time"

	"github.com/gofiber/fiber/v3"
	"github.com/gofiber/fiber/v3/extractors"
	"github.com/stretchr/testify/require"
	"github.com/valyala/fasthttp"
)

func TestConfigDefault(t *testing.T) {
	// Test default config
	cfg := configDefault()
	require.Equal(t, 30*time.Minute, cfg.IdleTimeout)
	require.NotNil(t, cfg.KeyGenerator)
	require.NotNil(t, cfg.Extractor)
	require.Equal(t, "session_id", cfg.Extractor.Key)
	require.Equal(t, "Lax", cfg.CookieSameSite)
}

func TestConfigDefaultWithCustomConfi

Default(customConfig)
	require.Equal(t, 48*time.Hour, cfg.IdleTimeout)
	require.NotNil(t, cfg.KeyGenerator)
	require.NotNil(t, cfg.Extractor)
	require.Equal(t, "X-Custom-Session", cfg.Extractor.Key)
}

func TestDefaultErrorHandler(t *testing.T) {
	// Creat

g(t *testing.T) {
	// Test custom config
	customConfig := Config{
		IdleTimeout:  48 * time.Hour,
		Extractor:    extractors.FromHeader("X-Custom-Session"),
		KeyGenerator: func() string { return "custom_key" },
	}
	cfg := config


un("Empty data", func(t *testing.T) {
		t.Parallel()
		d := acquireData()
		defer releaseData(d)
		keys := d.Keys()
		require.Empty(t, keys, "Expected no keys in empty data")
	})

	// Test case: Single key
	t.Run("Single key", func(t *testing.T) {
		t.Parallel()
		d := acquireData()
		defer releaseData(d)
		d.Set("key1", "value1")
		keys := d.Keys()
		require.Len(t, keys, 1, "Expected one key")
		require.Contains(t, keys, "key1", "Expected key1 to be present")
	})

	// Test case: Multiple keys
	t.Run("Multi

 keys")
		require.Contains(t, keys, "key1", "Expected key1 to be present")
		require.Contains(t, keys, "key2", "Expected key2 to be present")
		require.Contains(t, keys, "key3", "Expected key3 to be present")
	})

	// Test case: Concurrent access
	t.Run("C

ple keys", func(t *testing.T) {
		t.Parallel()
		d := acquireData()
		defer releaseData(d)
		d.Set("key1", "value1")
		d.Set("key2", "value2")
		d.Set("key3", "value3")
		keys := d.Keys()
		require.Len(t, keys, 3, "Expected three


"sync"

	"github.com/gofiber/fiber/v3"
	"github.com/gofiber/fiber/v3/internal/redact"
	"github.com/gofiber/fiber/v3/middleware/logger"
)

// Middleware holds session data and configuration.
// Middleware serializes access to its internal state with a mutex, but it is
// request-scoped and must not be used after the request lifecycle ends.
type Middleware struct {
	Session     *Session
	ctx         fiber.Ctx
	config      Config
	mu          sync.RWMutex
	isDestroyed bool
}

// Context key for session middlew

e assertion fails.
	ErrTypeAssertionFailed = errors.New("failed to type-assert to *Middleware")

	// Pool for reusing middleware instances.
	middlewarePool = &sync.Pool{
		New: func() any {
			return &Middleware{}
		},
	}
)

// New initializes session midd

are lookup.
type middlewareKey int

const (
	// middlewareContextKey is the key used to store the *Middleware in the context locals.
	middlewareContextKey middlewareKey = iota
)

var (
	// ErrTypeAssertionFailed occurs when a typ


type Session struct {
	ctx         fiber.Ctx     // fiber context
	config      *Store        // store configuration
	data        *data         // key value data
	id          string        // session id
	idleTimeout time.Duration // idleTimeout of this session
	mu          sync.RWMutex  // Mutex to protect non-data fields
	isFresh     bool          // if new session
}

type absExpirationKeyType int

const (
	// sessionIDContextKey is the key used to store the session ID in the context locals.
	absExpiration

	},
}

// acquireSession returns a new Session from the pool.
//
// Returns:
//   - *Session: The session object.
//
// Usage:
//
//	s := acquireSession()
func acquireSession() *Session {
	s := sessionPool.Get().(*Session) //nolint:forcetypeassert,errchec

Key absExpirationKeyType = iota
)

// Session pool for reusing byte buffers.
var byteBufferPool = sync.Pool{
	New: func() any {
		return new(bytes.Buffer)
	},
}

var sessionPool = sync.Pool{
	New: func() any {
		return &Session{}


 go test -run Test_Store_getSessionID
func Test_Store_getSessionID(t *testing.T) {
	t.Parallel()
	expectedID := "test-session-id"

	// fiber instance
	app := fiber.New()

	t.Run("from cookie", func(t *testing.T) {
		t.Parallel()
		// session store
		store := NewStore()
		// fiber context
		ctx := app.AcquireCtx(&fasthttp.RequestCtx{})
		defer app.ReleaseCtx(ctx)

		// set cookie
		ctx.Request().Header.SetCookie(store.Extractor.Key, expectedID)

		require.Equal(t, expectedID, store.getSessionID(ctx))
	})

	t

efer app.ReleaseCtx(ctx)

		// set header
		ctx.Request().Header.Set(store.Extractor.Key, expectedID)

		require.Equal(t, expectedID, store.getSessionID(ctx))
	})

	t.Run("from url query", func(t *testing.T) {
		t.Parallel()
		// session store
		store := N

.Run("from header", func(t *testing.T) {
		t.Parallel()
		// session store
		store := NewStore(Config{
			Extractor: extractors.FromHeader("session_id"),
		})
		// fiber context
		ctx := app.AcquireCtx(&fasthttp.RequestCtx{})
		d


nsferEncoding, "TransferEncoding")
		assert.Equal(t, expectedHost, r.Host, "Host")
		assert.Equal(t, expectedRemoteAddr, r.RemoteAddr, "RemoteAddr")

		body, readErr := io.ReadAll(r.Body)
		assert.NoError(t, readErr)
		assert.Equal(t, expectedBody, string(body), "Body")
		assert.Equal(t, expectedURL, r.URL, "URL")
		assert.Equal(t, expectedContextValue, r.Context().Value(expectedContextKey), "Context")

		for k, expectedV := range expectedHeader {
			v := r.Header.Get(k)
			assert.Equal(t, expectedV, v, "He

	fiberH = setFiberContextValueMiddleware(fiberH, expectedContextKey, expectedContextValue)

	var fctx fasthttp.RequestCtx
	var req fasthttp.Request

	req.Header.SetMethod(expectedMethod)
	req.SetRequestURI(expectedRequestURI)
	req.Header.SetHost(expectedH

ader")
		}

		w.Header().Set("Header1", "value1")
		w.Header().Set("Header2", "value2")
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprintf(w, "request body is %q", body)
	}
	fiberH := HTTPHandlerFunc(http.HandlerFunc(nethttpH))