Source File
	app.go
Belonging Package
	github.com/gofiber/fiber/v2
// ⚡️ Fiber is an Express inspired web framework written in Go with ☕️// 🤖 Github Repository: https://github.com/gofiber/fiber// 📌 API Documentation: https://docs.gofiber.io// Package fiber is an Express inspired web framework built on top of Fasthttp,// the fastest HTTP engine for Go. Designed to ease things up for fast// development with zero memory allocation and performance in mind.package fiberimport ()// Version of current fiber packageconst Version = "2.50.0"// Handler defines a function to serve HTTP requests.type Handler = func(*Ctx) error// Map is a shortcut for map[string]interface{}, useful for JSON returnstype Map map[string]interface{}// Storage interface for communicating with different database/key-value// providerstype Storage interface {// Get gets the value for the given key.// `nil, nil` is returned when the key does not existGet(key string) ([]byte, error)// Set stores the given value for 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// Delete deletes the value for the given key.// It returns no error if the storage does not contain the key,Delete(key string) error// Reset resets the storage and delete all keys.Reset() error// Close closes the storage and will stop any running garbage// collectors and open connections.Close() error}// ErrorHandler defines a function that will process all errors// returned from any handlers in the stack//// cfg := fiber.Config{}// cfg.ErrorHandler = func(c *Ctx, err error) error {// code := StatusInternalServerError// var e *fiber.Error// if errors.As(err, &e) {// code = e.Code// }// c.Set(HeaderContentType, MIMETextPlainCharsetUTF8)// return c.Status(code).SendString(err.Error())// }// app := fiber.New(cfg)type ErrorHandler = func(*Ctx, error) error// Error represents an error that occurred while handling a request.type Error struct {Code int `json:"code"`Message string `json:"message"`}// App denotes the Fiber application.type App struct {mutex sync.Mutex// Route stack divided by HTTP methodsstack [][]*Route// Route stack divided by HTTP methods and route prefixestreeStack []map[string][]*Route// contains the information if the route stack has been changed to build the optimized treeroutesRefreshed bool// Amount of registered routesroutesCount uint32// Amount of registered handlershandlersCount uint32// Ctx poolpool sync.Pool// Fasthttp serverserver *fasthttp.Server// App configconfig Config// Converts string to a byte slicegetBytes func(s string) (b []byte)// Converts byte slice to a stringgetString func(b []byte) string// Hookshooks *Hooks// Latest route & grouplatestRoute *Route// TLS handlertlsHandler *TLSHandler// Mount fieldsmountFields *mountFields// Indicates if the value was explicitly configuredconfigured Config}// Config is a struct holding the server settings.type Config struct {// When set to true, this will spawn multiple Go processes listening on the same port.//// Default: falsePrefork bool `json:"prefork"`// Enables the "Server: value" HTTP header.//// Default: ""ServerHeader string `json:"server_header"`// When set to true, the router treats "/foo" and "/foo/" as different.// By default this is disabled and both "/foo" and "/foo/" will execute the same handler.//// Default: falseStrictRouting bool `json:"strict_routing"`// When set to true, enables case sensitive routing.// E.g. "/FoO" and "/foo" are treated as different routes.// By default this is disabled and both "/FoO" and "/foo" will execute the same handler.//// Default: falseCaseSensitive bool `json:"case_sensitive"`// When set to true, this relinquishes the 0-allocation promise in certain// cases in order to access the handler values (e.g. request bodies) in an// immutable fashion so that these values are available even if you return// from handler.//// Default: falseImmutable bool `json:"immutable"`// When set to true, converts all encoded characters in the route back// before setting the path for the context, so that the routing,// the returning of the current url from the context `ctx.Path()`// and the parameters `ctx.Params(%key%)` with decoded characters will work//// Default: falseUnescapePath bool `json:"unescape_path"`// Enable or disable ETag header generation, since both weak and strong etags are generated// using the same hashing method (CRC-32). Weak ETags are the default when enabled.//// Default: falseETag bool `json:"etag"`// Max body size that the server accepts.// -1 will decline any body size//// Default: 4 * 1024 * 1024BodyLimit int `json:"body_limit"`// Maximum number of concurrent connections.//// Default: 256 * 1024Concurrency int `json:"concurrency"`// Views is the interface that wraps the Render function.//// Default: nilViews Views `json:"-"`// Views Layout is the global layout for all template render until override on Render function.//// Default: ""ViewsLayout string `json:"views_layout"`// PassLocalsToViews Enables passing of the locals set on a fiber.Ctx to the template engine//// Default: falsePassLocalsToViews bool `json:"pass_locals_to_views"`// The amount of time allowed to read the full request including body.// It is reset after the request handler has returned.// The connection's read deadline is reset when the connection opens.//// Default: unlimitedReadTimeout time.Duration `json:"read_timeout"`// The maximum duration before timing out writes of the response.// It is reset after the request handler has returned.//// Default: unlimitedWriteTimeout time.Duration `json:"write_timeout"`// The maximum amount of time to wait for the next request when keep-alive is enabled.// If IdleTimeout is zero, the value of ReadTimeout is used.//// Default: unlimitedIdleTimeout time.Duration `json:"idle_timeout"`// Per-connection buffer size for requests' reading.// This also limits the maximum header size.// Increase this buffer if your clients send multi-KB RequestURIs// and/or multi-KB headers (for example, BIG cookies).//// Default: 4096ReadBufferSize int `json:"read_buffer_size"`// Per-connection buffer size for responses' writing.//// Default: 4096WriteBufferSize int `json:"write_buffer_size"`// CompressedFileSuffix adds suffix to the original file name and// tries saving the resulting compressed file under the new file name.//// Default: ".fiber.gz"CompressedFileSuffix string `json:"compressed_file_suffix"`// ProxyHeader will enable c.IP() to return the value of the given header key// By default c.IP() will return the Remote IP from the TCP connection// This property can be useful if you are behind a load balancer: X-Forwarded-*// NOTE: headers are easily spoofed and the detected IP addresses are unreliable.//// Default: ""ProxyHeader string `json:"proxy_header"`// GETOnly rejects all non-GET requests if set to true.// This option is useful as anti-DoS protection for servers// accepting only GET requests. The request size is limited// by ReadBufferSize if GETOnly is set.//// Default: falseGETOnly bool `json:"get_only"`// ErrorHandler is executed when an error is returned from fiber.Handler.//// Default: DefaultErrorHandlerErrorHandler ErrorHandler `json:"-"`// When set to true, disables keep-alive connections.// The server will close incoming connections after sending the first response to client.//// Default: falseDisableKeepalive bool `json:"disable_keepalive"`// When set to true, causes the default date header to be excluded from the response.//// Default: falseDisableDefaultDate bool `json:"disable_default_date"`// When set to true, causes the default Content-Type header to be excluded from the response.//// Default: falseDisableDefaultContentType bool `json:"disable_default_content_type"`// When set to true, disables header normalization.// By default all header names are normalized: conteNT-tYPE -> Content-Type.//// Default: falseDisableHeaderNormalizing bool `json:"disable_header_normalizing"`// When set to true, it will not print out the «Fiber» ASCII art and listening address.//// Default: falseDisableStartupMessage bool `json:"disable_startup_message"`// This function allows to setup app name for the app//// Default: nilAppName string `json:"app_name"`// StreamRequestBody enables request body streaming,// and calls the handler sooner when given body is// larger then the current limit.StreamRequestBody bool// Will not pre parse Multipart Form data if set to true.//// This option is useful for servers that desire to treat// multipart form data as a binary blob, or choose when to parse the data.//// Server pre parses multipart form data by default.DisablePreParseMultipartForm bool// Aggressively reduces memory usage at the cost of higher CPU usage// if set to true.//// Try enabling this option only if the server consumes too much memory// serving mostly idle keep-alive connections. This may reduce memory// usage by more than 50%.//// Default: falseReduceMemoryUsage bool `json:"reduce_memory_usage"`// FEATURE: v2.3.x// The router executes the same handler by default if StrictRouting or CaseSensitive is disabled.// Enabling RedirectFixedPath will change this behavior into a client redirect to the original route path.// Using the status code 301 for GET requests and 308 for all other request methods.//// Default: false// RedirectFixedPath bool// When set by an external client of Fiber it will use the provided implementation of a// JSONMarshal//// Allowing for flexibility in using another json library for encoding// Default: json.MarshalJSONEncoder utils.JSONMarshal `json:"-"`// When set by an external client of Fiber it will use the provided implementation of a// JSONUnmarshal//// Allowing for flexibility in using another json library for decoding// Default: json.UnmarshalJSONDecoder utils.JSONUnmarshal `json:"-"`// XMLEncoder set by an external client of Fiber it will use the provided implementation of a// XMLMarshal//// Allowing for flexibility in using another XML library for encoding// Default: xml.MarshalXMLEncoder utils.XMLMarshal `json:"-"`// Known networks are "tcp", "tcp4" (IPv4-only), "tcp6" (IPv6-only)// WARNING: When prefork is set to true, only "tcp4" and "tcp6" can be chose.//// Default: NetworkTCP4Network string// If you find yourself behind some sort of proxy, like a load balancer,// then certain header information may be sent to you using special X-Forwarded-* headers or the Forwarded header.// For example, the Host HTTP header is usually used to return the requested host.// But when you’re behind a proxy, the actual host may be stored in an X-Forwarded-Host header.//// If you are behind a proxy, you should enable TrustedProxyCheck to prevent header spoofing.// If you enable EnableTrustedProxyCheck and leave TrustedProxies empty Fiber will skip// all headers that could be spoofed.// If request ip in TrustedProxies whitelist then:// 1. c.Protocol() get value from X-Forwarded-Proto, X-Forwarded-Protocol, X-Forwarded-Ssl or X-Url-Scheme header// 2. c.IP() get value from ProxyHeader header.// 3. c.Hostname() get value from X-Forwarded-Host header// But if request ip NOT in Trusted Proxies whitelist then:// 1. c.Protocol() WON't get value from X-Forwarded-Proto, X-Forwarded-Protocol, X-Forwarded-Ssl or X-Url-Scheme header,// will return https in case when tls connection is handled by the app, of http otherwise// 2. c.IP() WON'T get value from ProxyHeader header, will return RemoteIP() from fasthttp context// 3. c.Hostname() WON'T get value from X-Forwarded-Host header, fasthttp.Request.URI().Host()// will be used to get the hostname.//// Default: falseEnableTrustedProxyCheck bool `json:"enable_trusted_proxy_check"`// Read EnableTrustedProxyCheck doc.//// Default: []stringTrustedProxies []string `json:"trusted_proxies"`trustedProxiesMap map[string]struct{}trustedProxyRanges []*net.IPNet// If set to true, c.IP() and c.IPs() will validate IP addresses before returning them.// Also, c.IP() will return only the first valid IP rather than just the raw header// WARNING: this has a performance cost associated with it.//// Default: falseEnableIPValidation bool `json:"enable_ip_validation"`// If set to true, will print all routes with their method, path and handler.// Default: falseEnablePrintRoutes bool `json:"enable_print_routes"`// You can define custom color scheme. They'll be used for startup message, route list and some middlewares.//// Optional. Default: DefaultColorsColorScheme Colors `json:"color_scheme"`// RequestMethods provides customizibility for HTTP methods. You can add/remove methods as you wish.//// Optional. Default: DefaultMethodsRequestMethods []string// EnableSplittingOnParsers splits the query/body/header parameters by comma when it's true.// For example, you can use it to parse multiple values from a query parameter like this:// /api?foo=bar,baz == foo[]=bar&foo[]=baz//// Optional. Default: falseEnableSplittingOnParsers bool `json:"enable_splitting_on_parsers"`}// Static defines configuration options when defining static assets.type Static struct {// When set to true, the server tries minimizing CPU usage by caching compressed files.// This works differently than the github.com/gofiber/compression middleware.// Optional. Default value falseCompress bool `json:"compress"`// When set to true, enables byte range requests.// Optional. Default value falseByteRange bool `json:"byte_range"`// When set to true, enables directory browsing.// Optional. Default value false.Browse bool `json:"browse"`// When set to true, enables direct download.// Optional. Default value false.Download bool `json:"download"`// The name of the index file for serving a directory.// Optional. Default value "index.html".Index string `json:"index"`// Expiration duration for inactive file handlers.// Use a negative time.Duration to disable it.//// Optional. Default value 10 * time.Second.CacheDuration time.Duration `json:"cache_duration"`// The value for the Cache-Control HTTP-header// that is set on the file response. MaxAge is defined in seconds.//// Optional. Default value 0.MaxAge int `json:"max_age"`// ModifyResponse defines a function that allows you to alter the response.//// Optional. Default: nilModifyResponse Handler// Next defines a function to skip this middleware when returned true.//// Optional. Default: nilNext func(c *Ctx) bool}// RouteMessage is some message need to be print when server startstype RouteMessage struct {name stringmethod stringpath stringhandlers string}// Default Config valuesconst (DefaultBodyLimit = 4 * 1024 * 1024DefaultConcurrency = 256 * 1024DefaultReadBufferSize = 4096DefaultWriteBufferSize = 4096DefaultCompressedFileSuffix = ".fiber.gz")// HTTP methods enabled by defaultvar DefaultMethods = []string{MethodGet,MethodHead,MethodPost,MethodPut,MethodDelete,MethodConnect,MethodOptions,MethodTrace,MethodPatch,}// DefaultErrorHandler that process return errors from handlersfunc ( *Ctx, error) error {:= StatusInternalServerErrorvar *Errorif errors.As(, &) {= .Code}.Set(HeaderContentType, MIMETextPlainCharsetUTF8)return .Status().SendString(.Error())}// New creates a new Fiber named instance.//// app := fiber.New()//// You can pass optional configuration options by passing a Config struct://// app := fiber.New(fiber.Config{// Prefork: true,// ServerHeader: "Fiber",// })func ( ...Config) *App {// Create a new app:= &App{// Create Ctx poolpool: sync.Pool{New: func() interface{} {return new(Ctx)},},// Create configconfig: Config{},getBytes: utils.UnsafeBytes,getString: utils.UnsafeString,latestRoute: &Route{},}// Define hooks.hooks = newHooks()// Define mountFields.mountFields = newMountFields()// Override config if providedif len() > 0 {.config = [0]}// Initialize configured before defaults are set.configured = .configif .config.ETag {if !IsChild() {log.Warn("Config.ETag is deprecated since v2.0.6, please use 'middleware/etag'.")}}// Override default valuesif .config.BodyLimit == 0 {.config.BodyLimit = DefaultBodyLimit}if .config.Concurrency <= 0 {.config.Concurrency = DefaultConcurrency}if .config.ReadBufferSize <= 0 {.config.ReadBufferSize = DefaultReadBufferSize}if .config.WriteBufferSize <= 0 {.config.WriteBufferSize = DefaultWriteBufferSize}if .config.CompressedFileSuffix == "" {.config.CompressedFileSuffix = DefaultCompressedFileSuffix}if .config.Immutable {.getBytes, .getString = getBytesImmutable, getStringImmutable}if .config.ErrorHandler == nil {.config.ErrorHandler = DefaultErrorHandler}if .config.JSONEncoder == nil {.config.JSONEncoder = json.Marshal}if .config.JSONDecoder == nil {.config.JSONDecoder = json.Unmarshal}if .config.XMLEncoder == nil {.config.XMLEncoder = xml.Marshal}if .config.Network == "" {.config.Network = NetworkTCP4}if len(.config.RequestMethods) == 0 {.config.RequestMethods = DefaultMethods}.config.trustedProxiesMap = make(map[string]struct{}, len(.config.TrustedProxies))for , := range .config.TrustedProxies {.handleTrustedProxy()}// Create router stack.stack = make([][]*Route, len(.config.RequestMethods)).treeStack = make([]map[string][]*Route, len(.config.RequestMethods))// Override colors.config.ColorScheme = defaultColors(.config.ColorScheme)// Init app.init()// Return appreturn}// Adds an ip address to trustedProxyRanges or trustedProxiesMap based on whether it is an IP range or notfunc ( *App) ( string) {if strings.Contains(, "/") {, , := net.ParseCIDR()if != nil {log.Warnf("IP range %q could not be parsed: %v", , )} else {.config.trustedProxyRanges = append(.config.trustedProxyRanges, )}} else {.config.trustedProxiesMap[] = struct{}{}}}// SetTLSHandler You can use SetTLSHandler to use ClientHelloInfo when using TLS with Listener.func ( *App) ( *TLSHandler) {// Attach the tlsHandler to the config.mutex.Lock().tlsHandler =.mutex.Unlock()}// Name Assign name to specific route.func ( *App) ( string) Router {.mutex.Lock()defer .mutex.Unlock()for , := range .stack {for , := range {if .Path == .latestRoute.Path {.Name =if .group != nil {.Name = .group.name + .Name}}}}if := .hooks.executeOnNameHooks(*.latestRoute); != nil {panic()}return}// GetRoute Get route by namefunc ( *App) ( string) Route {for , := range .stack {for , := range {if .Name == {return *}}}return Route{}}// GetRoutes Get all routes. When filterUseOption equal to true, it will filter the routes registered by the middleware.func ( *App) ( ...bool) []Route {var []Routevar boolif len() != 0 {= [0]}for , := range .stack {for , := range {if && .use {continue}= append(, *)}}return}// Use registers a middleware route that will match requests// with the provided prefix (which is optional and defaults to "/").//// app.Use(func(c *fiber.Ctx) error {// return c.Next()// })// app.Use("/api", func(c *fiber.Ctx) error {// return c.Next()// })// app.Use("/api", handler, func(c *fiber.Ctx) error {// return c.Next()// })//// This method will match all HTTP verbs: GET, POST, PUT, HEAD etc...func ( *App) ( ...interface{}) Router {var stringvar []stringvar []Handlerfor := 0; < len(); ++ {switch arg := [].(type) {case string:=case []string:=case Handler:= append(, )default:panic(fmt.Sprintf("use: invalid handler %v\n", reflect.TypeOf()))}}if len() == 0 {= append(, )}for , := range {.register(methodUse, , nil, ...)}return}// Get registers a route for GET methods that requests a representation// of the specified resource. Requests using GET should only retrieve data.func ( *App) ( string, ...Handler) Router {return .Head(, ...).Add(MethodGet, , ...)}// Head registers a route for HEAD methods that asks for a response identical// to that of a GET request, but without the response body.func ( *App) ( string, ...Handler) Router {return .Add(MethodHead, , ...)}// Post registers a route for POST methods that is used to submit an entity to the// specified resource, often causing a change in state or side effects on the server.func ( *App) ( string, ...Handler) Router {return .Add(MethodPost, , ...)}// Put registers a route for PUT methods that replaces all current representations// of the target resource with the request payload.func ( *App) ( string, ...Handler) Router {return .Add(MethodPut, , ...)}// Delete registers a route for DELETE methods that deletes the specified resource.func ( *App) ( string, ...Handler) Router {return .Add(MethodDelete, , ...)}// Connect registers a route for CONNECT methods that establishes a tunnel to the// server identified by the target resource.func ( *App) ( string, ...Handler) Router {return .Add(MethodConnect, , ...)}// Options registers a route for OPTIONS methods that is used to describe the// communication options for the target resource.func ( *App) ( string, ...Handler) Router {return .Add(MethodOptions, , ...)}// Trace registers a route for TRACE methods that performs a message loop-back// test along the path to the target resource.func ( *App) ( string, ...Handler) Router {return .Add(MethodTrace, , ...)}// Patch registers a route for PATCH methods that is used to apply partial// modifications to a resource.func ( *App) ( string, ...Handler) Router {return .Add(MethodPatch, , ...)}// Add allows you to specify a HTTP method to register a routefunc ( *App) (, string, ...Handler) Router {.register(, , nil, ...)return}// Static will create a file server serving static filesfunc ( *App) (, string, ...Static) Router {.registerStatic(, , ...)return}// All will register the handler on all HTTP methodsfunc ( *App) ( string, ...Handler) Router {for , := range .config.RequestMethods {_ = .Add(, , ...)}return}// Group is used for Routes with common prefix to define a new sub-router with optional middleware.//// api := app.Group("/api")// api.Get("/users", handler)func ( *App) ( string, ...Handler) Router {:= &Group{Prefix: , app: }if len() > 0 {.register(methodUse, , , ...)}if := .hooks.executeOnGroupHooks(*); != nil {panic()}return}// Route is used to define routes with a common prefix inside the common function.// Uses Group method to define new sub-router.func ( *App) ( string, func( Router), ...string) Router {// Create new group:= .Group()if len() > 0 {.Name([0])}// Define routes()return}// Error makes it compatible with the `error` interface.func ( *Error) () string {return .Message}// NewError creates a new Error instance with an optional messagefunc ( int, ...string) *Error {:= &Error{Code: ,Message: utils.StatusMessage(),}if len() > 0 {.Message = [0]}return}// Config returns the app config as value ( read-only ).func ( *App) () Config {return .config}// Handler returns the server handler.func ( *App) () fasthttp.RequestHandler { //revive:disable-line:confusing-naming // Having both a Handler() (uppercase) and a handler() (lowercase) is fine. TODO: Use nolint:revive directive instead. See https://github.com/golangci/golangci-lint/issues/3476// prepare the server for the start.startupProcess()return .handler}// Stack returns the raw router stack.func ( *App) () [][]*Route {return .stack}// HandlersCount returns the amount of registered handlers.func ( *App) () uint32 {return .handlersCount}// Shutdown gracefully shuts down the server without interrupting any active connections.// Shutdown works by first closing all open listeners and then waiting indefinitely for all connections to return to idle before shutting down.//// Make sure the program doesn't exit and waits instead for Shutdown to return.//// Shutdown does not close keepalive connections so its recommended to set ReadTimeout to something else than 0.func ( *App) () error {return .ShutdownWithContext(context.Background())}// ShutdownWithTimeout gracefully shuts down the server without interrupting any active connections. However, if the timeout is exceeded,// ShutdownWithTimeout will forcefully close any active connections.// ShutdownWithTimeout works by first closing all open listeners and then waiting for all connections to return to idle before shutting down.//// Make sure the program doesn't exit and waits instead for ShutdownWithTimeout to return.//// ShutdownWithTimeout does not close keepalive connections so its recommended to set ReadTimeout to something else than 0.func ( *App) ( time.Duration) error {, := context.WithTimeout(context.Background(), )defer ()return .ShutdownWithContext()}// ShutdownWithContext shuts down the server including by force if the context's deadline is exceeded.//// Make sure the program doesn't exit and waits instead for ShutdownWithTimeout to return.//// ShutdownWithContext does not close keepalive connections so its recommended to set ReadTimeout to something else than 0.func ( *App) ( context.Context) error {if .hooks != nil {defer .hooks.executeOnShutdownHooks()}.mutex.Lock()defer .mutex.Unlock()if .server == nil {return fmt.Errorf("shutdown: server is not running")}return .server.ShutdownWithContext()}// Server returns the underlying fasthttp serverfunc ( *App) () *fasthttp.Server {return .server}// Hooks returns the hook struct to register hooks.func ( *App) () *Hooks {return .hooks}// Test is used for internal debugging by passing a *http.Request.// Timeout is optional and defaults to 1s, -1 will disable it completely.func ( *App) ( *http.Request, ...int) (*http.Response, error) {// Set timeout:= 1000if len() > 0 {= [0]}// Add Content-Length if not provided with bodyif .Body != http.NoBody && .Header.Get(HeaderContentLength) == "" {.Header.Add(HeaderContentLength, strconv.FormatInt(.ContentLength, 10))}// Dump raw http request, := httputil.DumpRequest(, true)if != nil {return nil, fmt.Errorf("failed to dump request: %w", )}// Create test connection:= new(testConn)// Write raw http requestif , := .r.Write(); != nil {return nil, fmt.Errorf("failed to write: %w", )}// prepare the server for the start.startupProcess()// Serve conn to server:= make(chan error)go func() {var booldefer func() {if ! {<- fmt.Errorf("runtime.Goexit() called in handler or server panic")}}()<- .server.ServeConn()= true}()// Wait for callbackif >= 0 {// With timeoutselect {case = <-:case <-time.After(time.Duration() * time.Millisecond):return nil, fmt.Errorf("test: timeout error %vms", )}} else {// Without timeout= <-}// Check for errorsif != nil && !errors.Is(, fasthttp.ErrGetOnly) {return nil,}// Read response:= bufio.NewReader(&.w)// Convert raw http response to *http.Response, := http.ReadResponse(, )if != nil {return nil, fmt.Errorf("failed to read response: %w", )}return , nil}type disableLogger struct{}func (*disableLogger) ( string, ...interface{}) {// fmt.Println(fmt.Sprintf(format, args...))}func ( *App) () *App {// lock application.mutex.Lock()// Only load templates if a view engine is specifiedif .config.Views != nil {if := .config.Views.Load(); != nil {log.Warnf("failed to load views: %v", )}}// create fasthttp server.server = &fasthttp.Server{Logger: &disableLogger{},LogAllErrors: false,ErrorHandler: .serverErrorHandler,}// fasthttp server settings.server.Handler = .handler.server.Name = .config.ServerHeader.server.Concurrency = .config.Concurrency.server.NoDefaultDate = .config.DisableDefaultDate.server.NoDefaultContentType = .config.DisableDefaultContentType.server.DisableHeaderNamesNormalizing = .config.DisableHeaderNormalizing.server.DisableKeepalive = .config.DisableKeepalive.server.MaxRequestBodySize = .config.BodyLimit.server.NoDefaultServerHeader = .config.ServerHeader == "".server.ReadTimeout = .config.ReadTimeout.server.WriteTimeout = .config.WriteTimeout.server.IdleTimeout = .config.IdleTimeout.server.ReadBufferSize = .config.ReadBufferSize.server.WriteBufferSize = .config.WriteBufferSize.server.GetOnly = .config.GETOnly.server.ReduceMemoryUsage = .config.ReduceMemoryUsage.server.StreamRequestBody = .config.StreamRequestBody.server.DisablePreParseMultipartForm = .config.DisablePreParseMultipartForm// unlock application.mutex.Unlock()return}// ErrorHandler is the application's method in charge of finding the// appropriate handler for the given request. It searches any mounted// sub fibers by their prefixes and if it finds a match, it uses that// error handler. Otherwise it uses the configured error handler for// the app, which if not set is the DefaultErrorHandler.func ( *App) ( *Ctx, error) error {var (ErrorHandlerint)for , := range .mountFields.appList {if != "" && strings.HasPrefix(.path, ) {:= len(strings.Split(, "/"))if <= {if .configured.ErrorHandler != nil {= .config.ErrorHandler}=}}}if != nil {return (, )}return .config.ErrorHandler(, )}// serverErrorHandler is a wrapper around the application's error handler method// user for the fasthttp server configuration. It maps a set of fasthttp errors to fiber// errors before calling the application's error handler method.func ( *App) ( *fasthttp.RequestCtx, error) {:= .AcquireCtx()defer .ReleaseCtx()var (*net.OpErrornet.Error)switch {case errors.As(, new(*fasthttp.ErrSmallBuffer)):= ErrRequestHeaderFieldsTooLargecase errors.As(, &) && .Timeout():= ErrRequestTimeoutcase errors.As(, &):= ErrBadGatewaycase errors.Is(, fasthttp.ErrBodyTooLarge):= ErrRequestEntityTooLargecase errors.Is(, fasthttp.ErrGetOnly):= ErrMethodNotAllowedcase strings.Contains(.Error(), "timeout"):= ErrRequestTimeoutdefault:= NewError(StatusBadRequest, .Error())}if := .ErrorHandler(, ); != nil {log.Errorf("serverErrorHandler: failed to call ErrorHandler: %v", )_ = .SendStatus(StatusInternalServerError) //nolint:errcheck // It is fine to ignore the error herereturn}}// startupProcess Is the method which executes all the necessary processes just before the start of the server.func ( *App) () *App {.mutex.Lock()defer .mutex.Unlock().mountStartupProcess()// build route tree stack.buildTree()return}// Run onListen hooks. If they return an error, panic.func ( *App) ( ListenData) {if := .hooks.executeOnListenHooks(); != nil {panic()}}
|  | The pages are generated with Golds v0.6.7. (GOOS=linux GOARCH=amd64) Golds is a Go 101 project developed by Tapir Liu. PR and bug reports are welcome and can be submitted to the issue list. Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds. |