github.com/gofiber/fiber/v2@v2.47.0/app.go (about)

     1  // ⚡️ Fiber is an Express inspired web framework written in Go with ☕️
     2  // 🤖 Github Repository: https://github.com/gofiber/fiber
     3  // 📌 API Documentation: https://docs.gofiber.io
     4  
     5  // Package fiber is an Express inspired web framework built on top of Fasthttp,
     6  // the fastest HTTP engine for Go. Designed to ease things up for fast
     7  // development with zero memory allocation and performance in mind.
     8  package fiber
     9  
    10  import (
    11  	"bufio"
    12  	"context"
    13  	"encoding/json"
    14  	"encoding/xml"
    15  	"errors"
    16  	"fmt"
    17  	"log"
    18  	"net"
    19  	"net/http"
    20  	"net/http/httputil"
    21  	"reflect"
    22  	"strconv"
    23  	"strings"
    24  	"sync"
    25  	"time"
    26  
    27  	"github.com/gofiber/fiber/v2/utils"
    28  
    29  	"github.com/valyala/fasthttp"
    30  )
    31  
    32  // Version of current fiber package
    33  const Version = "2.47.0"
    34  
    35  // Handler defines a function to serve HTTP requests.
    36  type Handler = func(*Ctx) error
    37  
    38  // Map is a shortcut for map[string]interface{}, useful for JSON returns
    39  type Map map[string]interface{}
    40  
    41  // Storage interface for communicating with different database/key-value
    42  // providers
    43  type Storage interface {
    44  	// Get gets the value for the given key.
    45  	// `nil, nil` is returned when the key does not exist
    46  	Get(key string) ([]byte, error)
    47  
    48  	// Set stores the given value for the given key along
    49  	// with an expiration value, 0 means no expiration.
    50  	// Empty key or value will be ignored without an error.
    51  	Set(key string, val []byte, exp time.Duration) error
    52  
    53  	// Delete deletes the value for the given key.
    54  	// It returns no error if the storage does not contain the key,
    55  	Delete(key string) error
    56  
    57  	// Reset resets the storage and delete all keys.
    58  	Reset() error
    59  
    60  	// Close closes the storage and will stop any running garbage
    61  	// collectors and open connections.
    62  	Close() error
    63  }
    64  
    65  // ErrorHandler defines a function that will process all errors
    66  // returned from any handlers in the stack
    67  //
    68  //	cfg := fiber.Config{}
    69  //	cfg.ErrorHandler = func(c *Ctx, err error) error {
    70  //	 code := StatusInternalServerError
    71  //	 var e *fiber.Error
    72  //	 if errors.As(err, &e) {
    73  //	   code = e.Code
    74  //	 }
    75  //	 c.Set(HeaderContentType, MIMETextPlainCharsetUTF8)
    76  //	 return c.Status(code).SendString(err.Error())
    77  //	}
    78  //	app := fiber.New(cfg)
    79  type ErrorHandler = func(*Ctx, error) error
    80  
    81  // Error represents an error that occurred while handling a request.
    82  type Error struct {
    83  	Code    int    `json:"code"`
    84  	Message string `json:"message"`
    85  }
    86  
    87  // App denotes the Fiber application.
    88  type App struct {
    89  	mutex sync.Mutex
    90  	// Route stack divided by HTTP methods
    91  	stack [][]*Route
    92  	// Route stack divided by HTTP methods and route prefixes
    93  	treeStack []map[string][]*Route
    94  	// contains the information if the route stack has been changed to build the optimized tree
    95  	routesRefreshed bool
    96  	// Amount of registered routes
    97  	routesCount uint32
    98  	// Amount of registered handlers
    99  	handlersCount uint32
   100  	// Ctx pool
   101  	pool sync.Pool
   102  	// Fasthttp server
   103  	server *fasthttp.Server
   104  	// App config
   105  	config Config
   106  	// Converts string to a byte slice
   107  	getBytes func(s string) (b []byte)
   108  	// Converts byte slice to a string
   109  	getString func(b []byte) string
   110  	// Hooks
   111  	hooks *Hooks
   112  	// Latest route & group
   113  	latestRoute *Route
   114  	// TLS handler
   115  	tlsHandler *TLSHandler
   116  	// Mount fields
   117  	mountFields *mountFields
   118  	// Indicates if the value was explicitly configured
   119  	configured Config
   120  }
   121  
   122  // Config is a struct holding the server settings.
   123  type Config struct {
   124  	// When set to true, this will spawn multiple Go processes listening on the same port.
   125  	//
   126  	// Default: false
   127  	Prefork bool `json:"prefork"`
   128  
   129  	// Enables the "Server: value" HTTP header.
   130  	//
   131  	// Default: ""
   132  	ServerHeader string `json:"server_header"`
   133  
   134  	// When set to true, the router treats "/foo" and "/foo/" as different.
   135  	// By default this is disabled and both "/foo" and "/foo/" will execute the same handler.
   136  	//
   137  	// Default: false
   138  	StrictRouting bool `json:"strict_routing"`
   139  
   140  	// When set to true, enables case sensitive routing.
   141  	// E.g. "/FoO" and "/foo" are treated as different routes.
   142  	// By default this is disabled and both "/FoO" and "/foo" will execute the same handler.
   143  	//
   144  	// Default: false
   145  	CaseSensitive bool `json:"case_sensitive"`
   146  
   147  	// When set to true, this relinquishes the 0-allocation promise in certain
   148  	// cases in order to access the handler values (e.g. request bodies) in an
   149  	// immutable fashion so that these values are available even if you return
   150  	// from handler.
   151  	//
   152  	// Default: false
   153  	Immutable bool `json:"immutable"`
   154  
   155  	// When set to true, converts all encoded characters in the route back
   156  	// before setting the path for the context, so that the routing,
   157  	// the returning of the current url from the context `ctx.Path()`
   158  	// and the parameters `ctx.Params(%key%)` with decoded characters will work
   159  	//
   160  	// Default: false
   161  	UnescapePath bool `json:"unescape_path"`
   162  
   163  	// Enable or disable ETag header generation, since both weak and strong etags are generated
   164  	// using the same hashing method (CRC-32). Weak ETags are the default when enabled.
   165  	//
   166  	// Default: false
   167  	ETag bool `json:"etag"`
   168  
   169  	// Max body size that the server accepts.
   170  	// -1 will decline any body size
   171  	//
   172  	// Default: 4 * 1024 * 1024
   173  	BodyLimit int `json:"body_limit"`
   174  
   175  	// Maximum number of concurrent connections.
   176  	//
   177  	// Default: 256 * 1024
   178  	Concurrency int `json:"concurrency"`
   179  
   180  	// Views is the interface that wraps the Render function.
   181  	//
   182  	// Default: nil
   183  	Views Views `json:"-"`
   184  
   185  	// Views Layout is the global layout for all template render until override on Render function.
   186  	//
   187  	// Default: ""
   188  	ViewsLayout string `json:"views_layout"`
   189  
   190  	// PassLocalsToViews Enables passing of the locals set on a fiber.Ctx to the template engine
   191  	//
   192  	// Default: false
   193  	PassLocalsToViews bool `json:"pass_locals_to_views"`
   194  
   195  	// The amount of time allowed to read the full request including body.
   196  	// It is reset after the request handler has returned.
   197  	// The connection's read deadline is reset when the connection opens.
   198  	//
   199  	// Default: unlimited
   200  	ReadTimeout time.Duration `json:"read_timeout"`
   201  
   202  	// The maximum duration before timing out writes of the response.
   203  	// It is reset after the request handler has returned.
   204  	//
   205  	// Default: unlimited
   206  	WriteTimeout time.Duration `json:"write_timeout"`
   207  
   208  	// The maximum amount of time to wait for the next request when keep-alive is enabled.
   209  	// If IdleTimeout is zero, the value of ReadTimeout is used.
   210  	//
   211  	// Default: unlimited
   212  	IdleTimeout time.Duration `json:"idle_timeout"`
   213  
   214  	// Per-connection buffer size for requests' reading.
   215  	// This also limits the maximum header size.
   216  	// Increase this buffer if your clients send multi-KB RequestURIs
   217  	// and/or multi-KB headers (for example, BIG cookies).
   218  	//
   219  	// Default: 4096
   220  	ReadBufferSize int `json:"read_buffer_size"`
   221  
   222  	// Per-connection buffer size for responses' writing.
   223  	//
   224  	// Default: 4096
   225  	WriteBufferSize int `json:"write_buffer_size"`
   226  
   227  	// CompressedFileSuffix adds suffix to the original file name and
   228  	// tries saving the resulting compressed file under the new file name.
   229  	//
   230  	// Default: ".fiber.gz"
   231  	CompressedFileSuffix string `json:"compressed_file_suffix"`
   232  
   233  	// ProxyHeader will enable c.IP() to return the value of the given header key
   234  	// By default c.IP() will return the Remote IP from the TCP connection
   235  	// This property can be useful if you are behind a load balancer: X-Forwarded-*
   236  	// NOTE: headers are easily spoofed and the detected IP addresses are unreliable.
   237  	//
   238  	// Default: ""
   239  	ProxyHeader string `json:"proxy_header"`
   240  
   241  	// GETOnly rejects all non-GET requests if set to true.
   242  	// This option is useful as anti-DoS protection for servers
   243  	// accepting only GET requests. The request size is limited
   244  	// by ReadBufferSize if GETOnly is set.
   245  	//
   246  	// Default: false
   247  	GETOnly bool `json:"get_only"`
   248  
   249  	// ErrorHandler is executed when an error is returned from fiber.Handler.
   250  	//
   251  	// Default: DefaultErrorHandler
   252  	ErrorHandler ErrorHandler `json:"-"`
   253  
   254  	// When set to true, disables keep-alive connections.
   255  	// The server will close incoming connections after sending the first response to client.
   256  	//
   257  	// Default: false
   258  	DisableKeepalive bool `json:"disable_keepalive"`
   259  
   260  	// When set to true, causes the default date header to be excluded from the response.
   261  	//
   262  	// Default: false
   263  	DisableDefaultDate bool `json:"disable_default_date"`
   264  
   265  	// When set to true, causes the default Content-Type header to be excluded from the response.
   266  	//
   267  	// Default: false
   268  	DisableDefaultContentType bool `json:"disable_default_content_type"`
   269  
   270  	// When set to true, disables header normalization.
   271  	// By default all header names are normalized: conteNT-tYPE -> Content-Type.
   272  	//
   273  	// Default: false
   274  	DisableHeaderNormalizing bool `json:"disable_header_normalizing"`
   275  
   276  	// When set to true, it will not print out the «Fiber» ASCII art and listening address.
   277  	//
   278  	// Default: false
   279  	DisableStartupMessage bool `json:"disable_startup_message"`
   280  
   281  	// This function allows to setup app name for the app
   282  	//
   283  	// Default: nil
   284  	AppName string `json:"app_name"`
   285  
   286  	// StreamRequestBody enables request body streaming,
   287  	// and calls the handler sooner when given body is
   288  	// larger then the current limit.
   289  	StreamRequestBody bool
   290  
   291  	// Will not pre parse Multipart Form data if set to true.
   292  	//
   293  	// This option is useful for servers that desire to treat
   294  	// multipart form data as a binary blob, or choose when to parse the data.
   295  	//
   296  	// Server pre parses multipart form data by default.
   297  	DisablePreParseMultipartForm bool
   298  
   299  	// Aggressively reduces memory usage at the cost of higher CPU usage
   300  	// if set to true.
   301  	//
   302  	// Try enabling this option only if the server consumes too much memory
   303  	// serving mostly idle keep-alive connections. This may reduce memory
   304  	// usage by more than 50%.
   305  	//
   306  	// Default: false
   307  	ReduceMemoryUsage bool `json:"reduce_memory_usage"`
   308  
   309  	// FEATURE: v2.3.x
   310  	// The router executes the same handler by default if StrictRouting or CaseSensitive is disabled.
   311  	// Enabling RedirectFixedPath will change this behavior into a client redirect to the original route path.
   312  	// Using the status code 301 for GET requests and 308 for all other request methods.
   313  	//
   314  	// Default: false
   315  	// RedirectFixedPath bool
   316  
   317  	// When set by an external client of Fiber it will use the provided implementation of a
   318  	// JSONMarshal
   319  	//
   320  	// Allowing for flexibility in using another json library for encoding
   321  	// Default: json.Marshal
   322  	JSONEncoder utils.JSONMarshal `json:"-"`
   323  
   324  	// When set by an external client of Fiber it will use the provided implementation of a
   325  	// JSONUnmarshal
   326  	//
   327  	// Allowing for flexibility in using another json library for decoding
   328  	// Default: json.Unmarshal
   329  	JSONDecoder utils.JSONUnmarshal `json:"-"`
   330  
   331  	// XMLEncoder set by an external client of Fiber it will use the provided implementation of a
   332  	// XMLMarshal
   333  	//
   334  	// Allowing for flexibility in using another XML library for encoding
   335  	// Default: xml.Marshal
   336  	XMLEncoder utils.XMLMarshal `json:"-"`
   337  
   338  	// Known networks are "tcp", "tcp4" (IPv4-only), "tcp6" (IPv6-only)
   339  	// WARNING: When prefork is set to true, only "tcp4" and "tcp6" can be chose.
   340  	//
   341  	// Default: NetworkTCP4
   342  	Network string
   343  
   344  	// If you find yourself behind some sort of proxy, like a load balancer,
   345  	// then certain header information may be sent to you using special X-Forwarded-* headers or the Forwarded header.
   346  	// For example, the Host HTTP header is usually used to return the requested host.
   347  	// But when you’re behind a proxy, the actual host may be stored in an X-Forwarded-Host header.
   348  	//
   349  	// If you are behind a proxy, you should enable TrustedProxyCheck to prevent header spoofing.
   350  	// If you enable EnableTrustedProxyCheck and leave TrustedProxies empty Fiber will skip
   351  	// all headers that could be spoofed.
   352  	// If request ip in TrustedProxies whitelist then:
   353  	//   1. c.Protocol() get value from X-Forwarded-Proto, X-Forwarded-Protocol, X-Forwarded-Ssl or X-Url-Scheme header
   354  	//   2. c.IP() get value from ProxyHeader header.
   355  	//   3. c.Hostname() get value from X-Forwarded-Host header
   356  	// But if request ip NOT in Trusted Proxies whitelist then:
   357  	//   1. c.Protocol() WON't get value from X-Forwarded-Proto, X-Forwarded-Protocol, X-Forwarded-Ssl or X-Url-Scheme header,
   358  	//    will return https in case when tls connection is handled by the app, of http otherwise
   359  	//   2. c.IP() WON'T get value from ProxyHeader header, will return RemoteIP() from fasthttp context
   360  	//   3. c.Hostname() WON'T get value from X-Forwarded-Host header, fasthttp.Request.URI().Host()
   361  	//    will be used to get the hostname.
   362  	//
   363  	// Default: false
   364  	EnableTrustedProxyCheck bool `json:"enable_trusted_proxy_check"`
   365  
   366  	// Read EnableTrustedProxyCheck doc.
   367  	//
   368  	// Default: []string
   369  	TrustedProxies     []string `json:"trusted_proxies"`
   370  	trustedProxiesMap  map[string]struct{}
   371  	trustedProxyRanges []*net.IPNet
   372  
   373  	// If set to true, c.IP() and c.IPs() will validate IP addresses before returning them.
   374  	// Also, c.IP() will return only the first valid IP rather than just the raw header
   375  	// WARNING: this has a performance cost associated with it.
   376  	//
   377  	// Default: false
   378  	EnableIPValidation bool `json:"enable_ip_validation"`
   379  
   380  	// If set to true, will print all routes with their method, path and handler.
   381  	// Default: false
   382  	EnablePrintRoutes bool `json:"enable_print_routes"`
   383  
   384  	// You can define custom color scheme. They'll be used for startup message, route list and some middlewares.
   385  	//
   386  	// Optional. Default: DefaultColors
   387  	ColorScheme Colors `json:"color_scheme"`
   388  
   389  	// RequestMethods provides customizibility for HTTP methods. You can add/remove methods as you wish.
   390  	//
   391  	// Optional. Default: DefaultMethods
   392  	RequestMethods []string
   393  }
   394  
   395  // Static defines configuration options when defining static assets.
   396  type Static struct {
   397  	// When set to true, the server tries minimizing CPU usage by caching compressed files.
   398  	// This works differently than the github.com/gofiber/compression middleware.
   399  	// Optional. Default value false
   400  	Compress bool `json:"compress"`
   401  
   402  	// When set to true, enables byte range requests.
   403  	// Optional. Default value false
   404  	ByteRange bool `json:"byte_range"`
   405  
   406  	// When set to true, enables directory browsing.
   407  	// Optional. Default value false.
   408  	Browse bool `json:"browse"`
   409  
   410  	// When set to true, enables direct download.
   411  	// Optional. Default value false.
   412  	Download bool `json:"download"`
   413  
   414  	// The name of the index file for serving a directory.
   415  	// Optional. Default value "index.html".
   416  	Index string `json:"index"`
   417  
   418  	// Expiration duration for inactive file handlers.
   419  	// Use a negative time.Duration to disable it.
   420  	//
   421  	// Optional. Default value 10 * time.Second.
   422  	CacheDuration time.Duration `json:"cache_duration"`
   423  
   424  	// The value for the Cache-Control HTTP-header
   425  	// that is set on the file response. MaxAge is defined in seconds.
   426  	//
   427  	// Optional. Default value 0.
   428  	MaxAge int `json:"max_age"`
   429  
   430  	// ModifyResponse defines a function that allows you to alter the response.
   431  	//
   432  	// Optional. Default: nil
   433  	ModifyResponse Handler
   434  
   435  	// Next defines a function to skip this middleware when returned true.
   436  	//
   437  	// Optional. Default: nil
   438  	Next func(c *Ctx) bool
   439  }
   440  
   441  // RouteMessage is some message need to be print when server starts
   442  type RouteMessage struct {
   443  	name     string
   444  	method   string
   445  	path     string
   446  	handlers string
   447  }
   448  
   449  // Default Config values
   450  const (
   451  	DefaultBodyLimit            = 4 * 1024 * 1024
   452  	DefaultConcurrency          = 256 * 1024
   453  	DefaultReadBufferSize       = 4096
   454  	DefaultWriteBufferSize      = 4096
   455  	DefaultCompressedFileSuffix = ".fiber.gz"
   456  )
   457  
   458  // HTTP methods enabled by default
   459  var DefaultMethods = []string{
   460  	MethodGet,
   461  	MethodHead,
   462  	MethodPost,
   463  	MethodPut,
   464  	MethodDelete,
   465  	MethodConnect,
   466  	MethodOptions,
   467  	MethodTrace,
   468  	MethodPatch,
   469  }
   470  
   471  // DefaultErrorHandler that process return errors from handlers
   472  func DefaultErrorHandler(c *Ctx, err error) error {
   473  	code := StatusInternalServerError
   474  	var e *Error
   475  	if errors.As(err, &e) {
   476  		code = e.Code
   477  	}
   478  	c.Set(HeaderContentType, MIMETextPlainCharsetUTF8)
   479  	return c.Status(code).SendString(err.Error())
   480  }
   481  
   482  // New creates a new Fiber named instance.
   483  //
   484  //	app := fiber.New()
   485  //
   486  // You can pass optional configuration options by passing a Config struct:
   487  //
   488  //	app := fiber.New(fiber.Config{
   489  //	    Prefork: true,
   490  //	    ServerHeader: "Fiber",
   491  //	})
   492  func New(config ...Config) *App {
   493  	// Create a new app
   494  	app := &App{
   495  		// Create Ctx pool
   496  		pool: sync.Pool{
   497  			New: func() interface{} {
   498  				return new(Ctx)
   499  			},
   500  		},
   501  		// Create config
   502  		config:      Config{},
   503  		getBytes:    utils.UnsafeBytes,
   504  		getString:   utils.UnsafeString,
   505  		latestRoute: &Route{},
   506  	}
   507  
   508  	// Define hooks
   509  	app.hooks = newHooks(app)
   510  
   511  	// Define mountFields
   512  	app.mountFields = newMountFields(app)
   513  
   514  	// Override config if provided
   515  	if len(config) > 0 {
   516  		app.config = config[0]
   517  	}
   518  
   519  	// Initialize configured before defaults are set
   520  	app.configured = app.config
   521  
   522  	if app.config.ETag {
   523  		if !IsChild() {
   524  			log.Printf("[Warning] Config.ETag is deprecated since v2.0.6, please use 'middleware/etag'.\n")
   525  		}
   526  	}
   527  
   528  	// Override default values
   529  	if app.config.BodyLimit == 0 {
   530  		app.config.BodyLimit = DefaultBodyLimit
   531  	}
   532  	if app.config.Concurrency <= 0 {
   533  		app.config.Concurrency = DefaultConcurrency
   534  	}
   535  	if app.config.ReadBufferSize <= 0 {
   536  		app.config.ReadBufferSize = DefaultReadBufferSize
   537  	}
   538  	if app.config.WriteBufferSize <= 0 {
   539  		app.config.WriteBufferSize = DefaultWriteBufferSize
   540  	}
   541  	if app.config.CompressedFileSuffix == "" {
   542  		app.config.CompressedFileSuffix = DefaultCompressedFileSuffix
   543  	}
   544  	if app.config.Immutable {
   545  		app.getBytes, app.getString = getBytesImmutable, getStringImmutable
   546  	}
   547  
   548  	if app.config.ErrorHandler == nil {
   549  		app.config.ErrorHandler = DefaultErrorHandler
   550  	}
   551  
   552  	if app.config.JSONEncoder == nil {
   553  		app.config.JSONEncoder = json.Marshal
   554  	}
   555  	if app.config.JSONDecoder == nil {
   556  		app.config.JSONDecoder = json.Unmarshal
   557  	}
   558  	if app.config.XMLEncoder == nil {
   559  		app.config.XMLEncoder = xml.Marshal
   560  	}
   561  	if app.config.Network == "" {
   562  		app.config.Network = NetworkTCP4
   563  	}
   564  	if len(app.config.RequestMethods) == 0 {
   565  		app.config.RequestMethods = DefaultMethods
   566  	}
   567  
   568  	app.config.trustedProxiesMap = make(map[string]struct{}, len(app.config.TrustedProxies))
   569  	for _, ipAddress := range app.config.TrustedProxies {
   570  		app.handleTrustedProxy(ipAddress)
   571  	}
   572  
   573  	// Create router stack
   574  	app.stack = make([][]*Route, len(app.config.RequestMethods))
   575  	app.treeStack = make([]map[string][]*Route, len(app.config.RequestMethods))
   576  
   577  	// Override colors
   578  	app.config.ColorScheme = defaultColors(app.config.ColorScheme)
   579  
   580  	// Init app
   581  	app.init()
   582  
   583  	// Return app
   584  	return app
   585  }
   586  
   587  // Adds an ip address to trustedProxyRanges or trustedProxiesMap based on whether it is an IP range or not
   588  func (app *App) handleTrustedProxy(ipAddress string) {
   589  	if strings.Contains(ipAddress, "/") {
   590  		_, ipNet, err := net.ParseCIDR(ipAddress)
   591  		if err != nil {
   592  			log.Printf("[Warning] IP range %q could not be parsed: %v\n", ipAddress, err)
   593  		} else {
   594  			app.config.trustedProxyRanges = append(app.config.trustedProxyRanges, ipNet)
   595  		}
   596  	} else {
   597  		app.config.trustedProxiesMap[ipAddress] = struct{}{}
   598  	}
   599  }
   600  
   601  // SetTLSHandler You can use SetTLSHandler to use ClientHelloInfo when using TLS with Listener.
   602  func (app *App) SetTLSHandler(tlsHandler *TLSHandler) {
   603  	// Attach the tlsHandler to the config
   604  	app.mutex.Lock()
   605  	app.tlsHandler = tlsHandler
   606  	app.mutex.Unlock()
   607  }
   608  
   609  // Name Assign name to specific route.
   610  func (app *App) Name(name string) Router {
   611  	app.mutex.Lock()
   612  	defer app.mutex.Unlock()
   613  
   614  	for _, routes := range app.stack {
   615  		for _, route := range routes {
   616  			if route.Path == app.latestRoute.path {
   617  				route.Name = name
   618  
   619  				if route.group != nil {
   620  					route.Name = route.group.name + route.Name
   621  				}
   622  			}
   623  		}
   624  	}
   625  
   626  	if err := app.hooks.executeOnNameHooks(*app.latestRoute); err != nil {
   627  		panic(err)
   628  	}
   629  
   630  	return app
   631  }
   632  
   633  // GetRoute Get route by name
   634  func (app *App) GetRoute(name string) Route {
   635  	for _, routes := range app.stack {
   636  		for _, route := range routes {
   637  			if route.Name == name {
   638  				return *route
   639  			}
   640  		}
   641  	}
   642  
   643  	return Route{}
   644  }
   645  
   646  // GetRoutes Get all routes. When filterUseOption equal to true, it will filter the routes registered by the middleware.
   647  func (app *App) GetRoutes(filterUseOption ...bool) []Route {
   648  	var rs []Route
   649  	var filterUse bool
   650  	if len(filterUseOption) != 0 {
   651  		filterUse = filterUseOption[0]
   652  	}
   653  	for _, routes := range app.stack {
   654  		for _, route := range routes {
   655  			if filterUse && route.use {
   656  				continue
   657  			}
   658  			rs = append(rs, *route)
   659  		}
   660  	}
   661  	return rs
   662  }
   663  
   664  // Use registers a middleware route that will match requests
   665  // with the provided prefix (which is optional and defaults to "/").
   666  //
   667  //	app.Use(func(c *fiber.Ctx) error {
   668  //	     return c.Next()
   669  //	})
   670  //	app.Use("/api", func(c *fiber.Ctx) error {
   671  //	     return c.Next()
   672  //	})
   673  //	app.Use("/api", handler, func(c *fiber.Ctx) error {
   674  //	     return c.Next()
   675  //	})
   676  //
   677  // This method will match all HTTP verbs: GET, POST, PUT, HEAD etc...
   678  func (app *App) Use(args ...interface{}) Router {
   679  	var prefix string
   680  	var prefixes []string
   681  	var handlers []Handler
   682  
   683  	for i := 0; i < len(args); i++ {
   684  		switch arg := args[i].(type) {
   685  		case string:
   686  			prefix = arg
   687  		case []string:
   688  			prefixes = arg
   689  		case Handler:
   690  			handlers = append(handlers, arg)
   691  		default:
   692  			panic(fmt.Sprintf("use: invalid handler %v\n", reflect.TypeOf(arg)))
   693  		}
   694  	}
   695  
   696  	if len(prefixes) == 0 {
   697  		prefixes = append(prefixes, prefix)
   698  	}
   699  
   700  	for _, prefix := range prefixes {
   701  		app.register(methodUse, prefix, nil, handlers...)
   702  	}
   703  
   704  	return app
   705  }
   706  
   707  // Get registers a route for GET methods that requests a representation
   708  // of the specified resource. Requests using GET should only retrieve data.
   709  func (app *App) Get(path string, handlers ...Handler) Router {
   710  	return app.Head(path, handlers...).Add(MethodGet, path, handlers...)
   711  }
   712  
   713  // Head registers a route for HEAD methods that asks for a response identical
   714  // to that of a GET request, but without the response body.
   715  func (app *App) Head(path string, handlers ...Handler) Router {
   716  	return app.Add(MethodHead, path, handlers...)
   717  }
   718  
   719  // Post registers a route for POST methods that is used to submit an entity to the
   720  // specified resource, often causing a change in state or side effects on the server.
   721  func (app *App) Post(path string, handlers ...Handler) Router {
   722  	return app.Add(MethodPost, path, handlers...)
   723  }
   724  
   725  // Put registers a route for PUT methods that replaces all current representations
   726  // of the target resource with the request payload.
   727  func (app *App) Put(path string, handlers ...Handler) Router {
   728  	return app.Add(MethodPut, path, handlers...)
   729  }
   730  
   731  // Delete registers a route for DELETE methods that deletes the specified resource.
   732  func (app *App) Delete(path string, handlers ...Handler) Router {
   733  	return app.Add(MethodDelete, path, handlers...)
   734  }
   735  
   736  // Connect registers a route for CONNECT methods that establishes a tunnel to the
   737  // server identified by the target resource.
   738  func (app *App) Connect(path string, handlers ...Handler) Router {
   739  	return app.Add(MethodConnect, path, handlers...)
   740  }
   741  
   742  // Options registers a route for OPTIONS methods that is used to describe the
   743  // communication options for the target resource.
   744  func (app *App) Options(path string, handlers ...Handler) Router {
   745  	return app.Add(MethodOptions, path, handlers...)
   746  }
   747  
   748  // Trace registers a route for TRACE methods that performs a message loop-back
   749  // test along the path to the target resource.
   750  func (app *App) Trace(path string, handlers ...Handler) Router {
   751  	return app.Add(MethodTrace, path, handlers...)
   752  }
   753  
   754  // Patch registers a route for PATCH methods that is used to apply partial
   755  // modifications to a resource.
   756  func (app *App) Patch(path string, handlers ...Handler) Router {
   757  	return app.Add(MethodPatch, path, handlers...)
   758  }
   759  
   760  // Add allows you to specify a HTTP method to register a route
   761  func (app *App) Add(method, path string, handlers ...Handler) Router {
   762  	app.register(method, path, nil, handlers...)
   763  
   764  	return app
   765  }
   766  
   767  // Static will create a file server serving static files
   768  func (app *App) Static(prefix, root string, config ...Static) Router {
   769  	app.registerStatic(prefix, root, config...)
   770  
   771  	return app
   772  }
   773  
   774  // All will register the handler on all HTTP methods
   775  func (app *App) All(path string, handlers ...Handler) Router {
   776  	for _, method := range app.config.RequestMethods {
   777  		_ = app.Add(method, path, handlers...)
   778  	}
   779  	return app
   780  }
   781  
   782  // Group is used for Routes with common prefix to define a new sub-router with optional middleware.
   783  //
   784  //	api := app.Group("/api")
   785  //	api.Get("/users", handler)
   786  func (app *App) Group(prefix string, handlers ...Handler) Router {
   787  	grp := &Group{Prefix: prefix, app: app}
   788  	if len(handlers) > 0 {
   789  		app.register(methodUse, prefix, grp, handlers...)
   790  	}
   791  	if err := app.hooks.executeOnGroupHooks(*grp); err != nil {
   792  		panic(err)
   793  	}
   794  
   795  	return grp
   796  }
   797  
   798  // Route is used to define routes with a common prefix inside the common function.
   799  // Uses Group method to define new sub-router.
   800  func (app *App) Route(prefix string, fn func(router Router), name ...string) Router {
   801  	// Create new group
   802  	group := app.Group(prefix)
   803  	if len(name) > 0 {
   804  		group.Name(name[0])
   805  	}
   806  
   807  	// Define routes
   808  	fn(group)
   809  
   810  	return group
   811  }
   812  
   813  // Error makes it compatible with the `error` interface.
   814  func (e *Error) Error() string {
   815  	return e.Message
   816  }
   817  
   818  // NewError creates a new Error instance with an optional message
   819  func NewError(code int, message ...string) *Error {
   820  	err := &Error{
   821  		Code:    code,
   822  		Message: utils.StatusMessage(code),
   823  	}
   824  	if len(message) > 0 {
   825  		err.Message = message[0]
   826  	}
   827  	return err
   828  }
   829  
   830  // Config returns the app config as value ( read-only ).
   831  func (app *App) Config() Config {
   832  	return app.config
   833  }
   834  
   835  // Handler returns the server handler.
   836  func (app *App) Handler() 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
   837  	// prepare the server for the start
   838  	app.startupProcess()
   839  	return app.handler
   840  }
   841  
   842  // Stack returns the raw router stack.
   843  func (app *App) Stack() [][]*Route {
   844  	return app.stack
   845  }
   846  
   847  // HandlersCount returns the amount of registered handlers.
   848  func (app *App) HandlersCount() uint32 {
   849  	return app.handlersCount
   850  }
   851  
   852  // Shutdown gracefully shuts down the server without interrupting any active connections.
   853  // Shutdown works by first closing all open listeners and then waiting indefinitely for all connections to return to idle before shutting down.
   854  //
   855  // Make sure the program doesn't exit and waits instead for Shutdown to return.
   856  //
   857  // Shutdown does not close keepalive connections so its recommended to set ReadTimeout to something else than 0.
   858  func (app *App) Shutdown() error {
   859  	return app.ShutdownWithContext(context.Background())
   860  }
   861  
   862  // ShutdownWithTimeout gracefully shuts down the server without interrupting any active connections. However, if the timeout is exceeded,
   863  // ShutdownWithTimeout will forcefully close any active connections.
   864  // ShutdownWithTimeout works by first closing all open listeners and then waiting for all connections to return to idle before shutting down.
   865  //
   866  // Make sure the program doesn't exit and waits instead for ShutdownWithTimeout to return.
   867  //
   868  // ShutdownWithTimeout does not close keepalive connections so its recommended to set ReadTimeout to something else than 0.
   869  func (app *App) ShutdownWithTimeout(timeout time.Duration) error {
   870  	ctx, cancelFunc := context.WithTimeout(context.Background(), timeout)
   871  	defer cancelFunc()
   872  	return app.ShutdownWithContext(ctx)
   873  }
   874  
   875  // ShutdownWithContext shuts down the server including by force if the context's deadline is exceeded.
   876  //
   877  // Make sure the program doesn't exit and waits instead for ShutdownWithTimeout to return.
   878  //
   879  // ShutdownWithContext does not close keepalive connections so its recommended to set ReadTimeout to something else than 0.
   880  func (app *App) ShutdownWithContext(ctx context.Context) error {
   881  	if app.hooks != nil {
   882  		defer app.hooks.executeOnShutdownHooks()
   883  	}
   884  
   885  	app.mutex.Lock()
   886  	defer app.mutex.Unlock()
   887  	if app.server == nil {
   888  		return fmt.Errorf("shutdown: server is not running")
   889  	}
   890  	return app.server.ShutdownWithContext(ctx)
   891  }
   892  
   893  // Server returns the underlying fasthttp server
   894  func (app *App) Server() *fasthttp.Server {
   895  	return app.server
   896  }
   897  
   898  // Hooks returns the hook struct to register hooks.
   899  func (app *App) Hooks() *Hooks {
   900  	return app.hooks
   901  }
   902  
   903  // Test is used for internal debugging by passing a *http.Request.
   904  // Timeout is optional and defaults to 1s, -1 will disable it completely.
   905  func (app *App) Test(req *http.Request, msTimeout ...int) (*http.Response, error) {
   906  	// Set timeout
   907  	timeout := 1000
   908  	if len(msTimeout) > 0 {
   909  		timeout = msTimeout[0]
   910  	}
   911  
   912  	// Add Content-Length if not provided with body
   913  	if req.Body != http.NoBody && req.Header.Get(HeaderContentLength) == "" {
   914  		req.Header.Add(HeaderContentLength, strconv.FormatInt(req.ContentLength, 10))
   915  	}
   916  
   917  	// Dump raw http request
   918  	dump, err := httputil.DumpRequest(req, true)
   919  	if err != nil {
   920  		return nil, fmt.Errorf("failed to dump request: %w", err)
   921  	}
   922  
   923  	// Create test connection
   924  	conn := new(testConn)
   925  
   926  	// Write raw http request
   927  	if _, err := conn.r.Write(dump); err != nil {
   928  		return nil, fmt.Errorf("failed to write: %w", err)
   929  	}
   930  	// prepare the server for the start
   931  	app.startupProcess()
   932  
   933  	// Serve conn to server
   934  	channel := make(chan error)
   935  	go func() {
   936  		var returned bool
   937  		defer func() {
   938  			if !returned {
   939  				channel <- fmt.Errorf("runtime.Goexit() called in handler or server panic")
   940  			}
   941  		}()
   942  
   943  		channel <- app.server.ServeConn(conn)
   944  		returned = true
   945  	}()
   946  
   947  	// Wait for callback
   948  	if timeout >= 0 {
   949  		// With timeout
   950  		select {
   951  		case err = <-channel:
   952  		case <-time.After(time.Duration(timeout) * time.Millisecond):
   953  			return nil, fmt.Errorf("test: timeout error %vms", timeout)
   954  		}
   955  	} else {
   956  		// Without timeout
   957  		err = <-channel
   958  	}
   959  
   960  	// Check for errors
   961  	if err != nil && !errors.Is(err, fasthttp.ErrGetOnly) {
   962  		return nil, err
   963  	}
   964  
   965  	// Read response
   966  	buffer := bufio.NewReader(&conn.w)
   967  
   968  	// Convert raw http response to *http.Response
   969  	res, err := http.ReadResponse(buffer, req)
   970  	if err != nil {
   971  		return nil, fmt.Errorf("failed to read response: %w", err)
   972  	}
   973  
   974  	return res, nil
   975  }
   976  
   977  type disableLogger struct{}
   978  
   979  func (*disableLogger) Printf(_ string, _ ...interface{}) {
   980  	// fmt.Println(fmt.Sprintf(format, args...))
   981  }
   982  
   983  func (app *App) init() *App {
   984  	// lock application
   985  	app.mutex.Lock()
   986  
   987  	// Only load templates if a view engine is specified
   988  	if app.config.Views != nil {
   989  		if err := app.config.Views.Load(); err != nil {
   990  			log.Printf("[Warning]: failed to load views: %v\n", err)
   991  		}
   992  	}
   993  
   994  	// create fasthttp server
   995  	app.server = &fasthttp.Server{
   996  		Logger:       &disableLogger{},
   997  		LogAllErrors: false,
   998  		ErrorHandler: app.serverErrorHandler,
   999  	}
  1000  
  1001  	// fasthttp server settings
  1002  	app.server.Handler = app.handler
  1003  	app.server.Name = app.config.ServerHeader
  1004  	app.server.Concurrency = app.config.Concurrency
  1005  	app.server.NoDefaultDate = app.config.DisableDefaultDate
  1006  	app.server.NoDefaultContentType = app.config.DisableDefaultContentType
  1007  	app.server.DisableHeaderNamesNormalizing = app.config.DisableHeaderNormalizing
  1008  	app.server.DisableKeepalive = app.config.DisableKeepalive
  1009  	app.server.MaxRequestBodySize = app.config.BodyLimit
  1010  	app.server.NoDefaultServerHeader = app.config.ServerHeader == ""
  1011  	app.server.ReadTimeout = app.config.ReadTimeout
  1012  	app.server.WriteTimeout = app.config.WriteTimeout
  1013  	app.server.IdleTimeout = app.config.IdleTimeout
  1014  	app.server.ReadBufferSize = app.config.ReadBufferSize
  1015  	app.server.WriteBufferSize = app.config.WriteBufferSize
  1016  	app.server.GetOnly = app.config.GETOnly
  1017  	app.server.ReduceMemoryUsage = app.config.ReduceMemoryUsage
  1018  	app.server.StreamRequestBody = app.config.StreamRequestBody
  1019  	app.server.DisablePreParseMultipartForm = app.config.DisablePreParseMultipartForm
  1020  
  1021  	// unlock application
  1022  	app.mutex.Unlock()
  1023  	return app
  1024  }
  1025  
  1026  // ErrorHandler is the application's method in charge of finding the
  1027  // appropriate handler for the given request. It searches any mounted
  1028  // sub fibers by their prefixes and if it finds a match, it uses that
  1029  // error handler. Otherwise it uses the configured error handler for
  1030  // the app, which if not set is the DefaultErrorHandler.
  1031  func (app *App) ErrorHandler(ctx *Ctx, err error) error {
  1032  	var (
  1033  		mountedErrHandler  ErrorHandler
  1034  		mountedPrefixParts int
  1035  	)
  1036  
  1037  	for prefix, subApp := range app.mountFields.appList {
  1038  		if prefix != "" && strings.HasPrefix(ctx.path, prefix) {
  1039  			parts := len(strings.Split(prefix, "/"))
  1040  			if mountedPrefixParts <= parts {
  1041  				if subApp.configured.ErrorHandler != nil {
  1042  					mountedErrHandler = subApp.config.ErrorHandler
  1043  				}
  1044  
  1045  				mountedPrefixParts = parts
  1046  			}
  1047  		}
  1048  	}
  1049  
  1050  	if mountedErrHandler != nil {
  1051  		return mountedErrHandler(ctx, err)
  1052  	}
  1053  
  1054  	return app.config.ErrorHandler(ctx, err)
  1055  }
  1056  
  1057  // serverErrorHandler is a wrapper around the application's error handler method
  1058  // user for the fasthttp server configuration. It maps a set of fasthttp errors to fiber
  1059  // errors before calling the application's error handler method.
  1060  func (app *App) serverErrorHandler(fctx *fasthttp.RequestCtx, err error) {
  1061  	c := app.AcquireCtx(fctx)
  1062  	defer app.ReleaseCtx(c)
  1063  
  1064  	var (
  1065  		errNetOP *net.OpError
  1066  		netErr   net.Error
  1067  	)
  1068  
  1069  	switch {
  1070  	case errors.As(err, new(*fasthttp.ErrSmallBuffer)):
  1071  		err = ErrRequestHeaderFieldsTooLarge
  1072  	case errors.As(err, &errNetOP) && errNetOP.Timeout():
  1073  		err = ErrRequestTimeout
  1074  	case errors.As(err, &netErr):
  1075  		err = ErrBadGateway
  1076  	case errors.Is(err, fasthttp.ErrBodyTooLarge):
  1077  		err = ErrRequestEntityTooLarge
  1078  	case errors.Is(err, fasthttp.ErrGetOnly):
  1079  		err = ErrMethodNotAllowed
  1080  	case strings.Contains(err.Error(), "timeout"):
  1081  		err = ErrRequestTimeout
  1082  	default:
  1083  		err = NewError(StatusBadRequest, err.Error())
  1084  	}
  1085  
  1086  	if catch := app.ErrorHandler(c, err); catch != nil {
  1087  		log.Printf("serverErrorHandler: failed to call ErrorHandler: %v\n", catch)
  1088  		_ = c.SendStatus(StatusInternalServerError) //nolint:errcheck // It is fine to ignore the error here
  1089  		return
  1090  	}
  1091  }
  1092  
  1093  // startupProcess Is the method which executes all the necessary processes just before the start of the server.
  1094  func (app *App) startupProcess() *App {
  1095  	app.mutex.Lock()
  1096  	defer app.mutex.Unlock()
  1097  
  1098  	app.mountStartupProcess()
  1099  
  1100  	// build route tree stack
  1101  	app.buildTree()
  1102  
  1103  	return app
  1104  }
  1105  
  1106  // Run onListen hooks. If they return an error, panic.
  1107  func (app *App) runOnListenHooks() {
  1108  	if err := app.hooks.executeOnListenHooks(); err != nil {
  1109  		panic(err)
  1110  	}
  1111  }