app.go 45 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457
  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. // Package fiber is an Express inspired web framework built on top of Fasthttp,
  5. // the fastest HTTP engine for Go. Designed to ease things up for fast
  6. // development with zero memory allocation and performance in mind.
  7. package fiber
  8. import (
  9. "bufio"
  10. "context"
  11. "encoding/json"
  12. "encoding/xml"
  13. "errors"
  14. "fmt"
  15. "io"
  16. "net"
  17. "net/http"
  18. "net/http/httputil"
  19. "os"
  20. "reflect"
  21. "strconv"
  22. "strings"
  23. "sync"
  24. "time"
  25. "unsafe"
  26. "github.com/gofiber/utils/v2"
  27. "github.com/valyala/fasthttp"
  28. "github.com/gofiber/fiber/v3/binder"
  29. "github.com/gofiber/fiber/v3/log"
  30. )
  31. // Version of current fiber package
  32. const Version = "3.1.0"
  33. // Handler defines a function to serve HTTP requests.
  34. type Handler = func(Ctx) error
  35. // Map is a shortcut for map[string]any, useful for JSON returns
  36. type Map map[string]any
  37. // ErrorHandler defines a function that will process all errors
  38. // returned from any handlers in the stack
  39. //
  40. // cfg := fiber.Config{}
  41. // cfg.ErrorHandler = func(c Ctx, err error) error {
  42. // code := StatusInternalServerError
  43. // var e *fiber.Error
  44. // if errors.As(err, &e) {
  45. // code = e.Code
  46. // }
  47. // c.Set(HeaderContentType, MIMETextPlainCharsetUTF8)
  48. // return c.Status(code).SendString(err.Error())
  49. // }
  50. // app := fiber.New(cfg)
  51. type ErrorHandler = func(Ctx, error) error
  52. // Error represents an error that occurred while handling a request.
  53. type Error struct {
  54. Message string `json:"message"`
  55. Code int `json:"code"`
  56. }
  57. // App denotes the Fiber application.
  58. type App struct {
  59. // App config
  60. config Config
  61. // Indicates if the value was explicitly configured
  62. configured Config
  63. // Ctx pool
  64. pool sync.Pool
  65. // Fasthttp server
  66. server *fasthttp.Server
  67. // Converts string to a byte slice
  68. toBytes func(s string) (b []byte)
  69. // Converts byte slice to a string
  70. toString func(b []byte) string
  71. // Hooks
  72. hooks *Hooks
  73. // Latest route & group
  74. latestRoute *Route
  75. // newCtxFunc
  76. newCtxFunc func(app *App) CustomCtx
  77. // TLS handler
  78. tlsHandler *TLSHandler
  79. // Mount fields
  80. mountFields *mountFields
  81. // state management
  82. state *State
  83. // Route stack divided by HTTP methods
  84. stack [][]*Route
  85. // customConstraints is a list of external constraints
  86. customConstraints []CustomConstraint
  87. // sendfiles stores configurations for handling ctx.SendFile operations
  88. sendfiles []*sendFileStore
  89. // custom binders
  90. customBinders []CustomBinder
  91. // Route stack divided by HTTP methods and route prefixes
  92. treeStack []map[int][]*Route
  93. // sendfilesMutex is a mutex used for sendfile operations
  94. sendfilesMutex sync.RWMutex
  95. mutex sync.Mutex
  96. // Amount of registered handlers
  97. handlersCount uint32
  98. // contains the information if the route stack has been changed to build the optimized tree
  99. routesRefreshed bool
  100. // hasCustomCtx tracks whether app uses a custom context implementation
  101. hasCustomCtx bool
  102. }
  103. // Config is a struct holding the server settings.
  104. type Config struct { //nolint:govet // Aligning the struct fields is not necessary. betteralign:ignore
  105. // Enables the "Server: value" HTTP header.
  106. //
  107. // Default: ""
  108. ServerHeader string `json:"server_header"`
  109. // When set to true, the router treats "/foo" and "/foo/" as different.
  110. // By default this is disabled and both "/foo" and "/foo/" will execute the same handler.
  111. //
  112. // Default: false
  113. StrictRouting bool `json:"strict_routing"`
  114. // When set to true, enables case-sensitive routing.
  115. // E.g. "/FoO" and "/foo" are treated as different routes.
  116. // By default this is disabled and both "/FoO" and "/foo" will execute the same handler.
  117. //
  118. // Default: false
  119. CaseSensitive bool `json:"case_sensitive"`
  120. // When set to true, disables automatic registration of HEAD routes for
  121. // every GET route.
  122. //
  123. // Default: false
  124. DisableHeadAutoRegister bool `json:"disable_head_auto_register"`
  125. // When set to true, this relinquishes the 0-allocation promise in certain
  126. // cases in order to access the handler values (e.g. request bodies) in an
  127. // immutable fashion so that these values are available even if you return
  128. // from handler.
  129. //
  130. // Default: false
  131. Immutable bool `json:"immutable"`
  132. // When set to true, converts all encoded characters in the route back
  133. // before setting the path for the context, so that the routing,
  134. // the returning of the current url from the context `ctx.Path()`
  135. // and the parameters `ctx.Params(%key%)` with decoded characters will work
  136. //
  137. // Default: false
  138. UnescapePath bool `json:"unescape_path"`
  139. // Max body size that the server accepts.
  140. // Zero or negative values fall back to the default limit.
  141. //
  142. // Default: 4 * 1024 * 1024
  143. BodyLimit int `json:"body_limit"`
  144. // MaxRanges sets the maximum number of ranges parsed from a Range header.
  145. // Zero or negative values fall back to the default limit.
  146. //
  147. // Default: 16
  148. MaxRanges int `json:"max_ranges"`
  149. // Maximum number of concurrent connections.
  150. //
  151. // Default: 256 * 1024
  152. Concurrency int `json:"concurrency"`
  153. // Views is the interface that wraps the Render function.
  154. //
  155. // Default: nil
  156. Views Views `json:"-"`
  157. // Views Layout is the global layout for all template render until override on Render function.
  158. //
  159. // Default: ""
  160. ViewsLayout string `json:"views_layout"`
  161. // PassLocalsToViews Enables passing of the locals set on a fiber.Ctx to the template engine
  162. //
  163. // Default: false
  164. PassLocalsToViews bool `json:"pass_locals_to_views"`
  165. // PassLocalsToContext controls whether StoreInContext also propagates values to
  166. // the request context.Context for Fiber-backed contexts.
  167. //
  168. // ValueFromContext for Fiber-backed contexts always reads from c.Locals().
  169. //
  170. // Default: false
  171. PassLocalsToContext bool `json:"pass_locals_to_context"`
  172. // The amount of time allowed to read the full request including body.
  173. // It is reset after the request handler has returned.
  174. // The connection's read deadline is reset when the connection opens.
  175. //
  176. // Default: unlimited
  177. ReadTimeout time.Duration `json:"read_timeout"`
  178. // The maximum duration before timing out writes of the response.
  179. // It is reset after the request handler has returned.
  180. //
  181. // Default: unlimited
  182. WriteTimeout time.Duration `json:"write_timeout"`
  183. // The maximum amount of time to wait for the next request when keep-alive is enabled.
  184. // If IdleTimeout is zero, the value of ReadTimeout is used.
  185. //
  186. // Default: unlimited
  187. IdleTimeout time.Duration `json:"idle_timeout"`
  188. // Per-connection buffer size for requests' reading.
  189. // This also limits the maximum header size.
  190. // Increase this buffer if your clients send multi-KB RequestURIs
  191. // and/or multi-KB headers (for example, BIG cookies).
  192. //
  193. // Default: 4096
  194. ReadBufferSize int `json:"read_buffer_size"`
  195. // Per-connection buffer size for responses' writing.
  196. //
  197. // Default: 4096
  198. WriteBufferSize int `json:"write_buffer_size"`
  199. // CompressedFileSuffixes adds suffix to the original file name and
  200. // tries saving the resulting compressed file under the new file name.
  201. //
  202. // Default: map[string]string{"gzip": ".fiber.gz", "br": ".fiber.br", "zstd": ".fiber.zst"}
  203. CompressedFileSuffixes map[string]string `json:"compressed_file_suffixes"`
  204. // ProxyHeader will enable c.IP() to return the value of the given header key
  205. // By default c.IP() will return the Remote IP from the TCP connection
  206. // This property can be useful if you are behind a load balancer: X-Forwarded-*
  207. // NOTE: headers are easily spoofed and the detected IP addresses are unreliable.
  208. //
  209. // Default: ""
  210. ProxyHeader string `json:"proxy_header"`
  211. // GETOnly rejects all non-GET requests if set to true.
  212. // This option is useful as anti-DoS protection for servers
  213. // accepting only GET requests. The request size is limited
  214. // by ReadBufferSize if GETOnly is set.
  215. //
  216. // Default: false
  217. GETOnly bool `json:"get_only"`
  218. // ErrorHandler is executed when an error is returned from fiber.Handler.
  219. //
  220. // Default: DefaultErrorHandler
  221. ErrorHandler ErrorHandler `json:"-"`
  222. // When set to true, disables keep-alive connections.
  223. // The server will close incoming connections after sending the first response to client.
  224. //
  225. // Default: false
  226. DisableKeepalive bool `json:"disable_keepalive"`
  227. // When set to true, causes the default date header to be excluded from the response.
  228. //
  229. // Default: false
  230. DisableDefaultDate bool `json:"disable_default_date"`
  231. // When set to true, causes the default Content-Type header to be excluded from the response.
  232. //
  233. // Default: false
  234. DisableDefaultContentType bool `json:"disable_default_content_type"`
  235. // When set to true, disables header normalization.
  236. // By default all header names are normalized: conteNT-tYPE -> Content-Type.
  237. //
  238. // Default: false
  239. DisableHeaderNormalizing bool `json:"disable_header_normalizing"`
  240. // This function allows to setup app name for the app
  241. //
  242. // Default: nil
  243. AppName string `json:"app_name"`
  244. // StreamRequestBody enables request body streaming,
  245. // and calls the handler sooner when given body is
  246. // larger than the current limit.
  247. //
  248. // Default: false
  249. StreamRequestBody bool
  250. // Will not pre parse Multipart Form data if set to true.
  251. //
  252. // This option is useful for servers that desire to treat
  253. // multipart form data as a binary blob, or choose when to parse the data.
  254. //
  255. // Server pre parses multipart form data by default.
  256. //
  257. // Default: false
  258. DisablePreParseMultipartForm bool
  259. // Aggressively reduces memory usage at the cost of higher CPU usage
  260. // if set to true.
  261. //
  262. // Try enabling this option only if the server consumes too much memory
  263. // serving mostly idle keep-alive connections. This may reduce memory
  264. // usage by more than 50%.
  265. //
  266. // Default: false
  267. ReduceMemoryUsage bool `json:"reduce_memory_usage"`
  268. // When set by an external client of Fiber it will use the provided implementation of a
  269. // JSONMarshal
  270. //
  271. // Allowing for flexibility in using another json library for encoding
  272. // Default: json.Marshal
  273. JSONEncoder utils.JSONMarshal `json:"-"`
  274. // When set by an external client of Fiber it will use the provided implementation of a
  275. // JSONUnmarshal
  276. //
  277. // Allowing for flexibility in using another json library for decoding
  278. // Default: json.Unmarshal
  279. JSONDecoder utils.JSONUnmarshal `json:"-"`
  280. // When set by an external client of Fiber it will use the provided implementation of a
  281. // MsgPackMarshal
  282. //
  283. // Allowing for flexibility in using another msgpack library for encoding
  284. // Default: binder.UnimplementedMsgpackMarshal
  285. MsgPackEncoder utils.MsgPackMarshal `json:"-"`
  286. // When set by an external client of Fiber it will use the provided implementation of a
  287. // MsgPackUnmarshal
  288. //
  289. // Allowing for flexibility in using another msgpack library for decoding
  290. // Default: binder.UnimplementedMsgpackUnmarshal
  291. MsgPackDecoder utils.MsgPackUnmarshal `json:"-"`
  292. // When set by an external client of Fiber it will use the provided implementation of a
  293. // CBORMarshal
  294. //
  295. // Allowing for flexibility in using another cbor library for encoding
  296. // Default: binder.UnimplementedCborMarshal
  297. CBOREncoder utils.CBORMarshal `json:"-"`
  298. // When set by an external client of Fiber it will use the provided implementation of a
  299. // CBORUnmarshal
  300. //
  301. // Allowing for flexibility in using another cbor library for decoding
  302. // Default: binder.UnimplementedCborUnmarshal
  303. CBORDecoder utils.CBORUnmarshal `json:"-"`
  304. // XMLEncoder set by an external client of Fiber it will use the provided implementation of a
  305. // XMLMarshal
  306. //
  307. // Allowing for flexibility in using another XML library for encoding
  308. // Default: xml.Marshal
  309. XMLEncoder utils.XMLMarshal `json:"-"`
  310. // XMLDecoder set by an external client of Fiber it will use the provided implementation of a
  311. // XMLUnmarshal
  312. //
  313. // Allowing for flexibility in using another XML library for decoding
  314. // Default: xml.Unmarshal
  315. XMLDecoder utils.XMLUnmarshal `json:"-"`
  316. // If you find yourself behind some sort of proxy, like a load balancer,
  317. // then certain header information may be sent to you using special X-Forwarded-* headers or the Forwarded header.
  318. // For example, the Host HTTP header is usually used to return the requested host.
  319. // But when you’re behind a proxy, the actual host may be stored in an X-Forwarded-Host header.
  320. //
  321. // If you are behind a proxy, you should enable TrustProxy to prevent header spoofing.
  322. // If you enable TrustProxy and do not provide a TrustProxyConfig, Fiber will skip
  323. // all headers that could be spoofed.
  324. // If the request IP is in the TrustProxyConfig.Proxies allowlist, then:
  325. // 1. c.Scheme() get value from X-Forwarded-Proto, X-Forwarded-Protocol, X-Forwarded-Ssl or X-Url-Scheme header
  326. // 2. c.IP() get value from ProxyHeader header.
  327. // 3. c.Host() and c.Hostname() get value from X-Forwarded-Host header
  328. // But if the request IP is NOT in the TrustProxyConfig.Proxies allowlist, then:
  329. // 1. c.Scheme() WON'T get value from X-Forwarded-Proto, X-Forwarded-Protocol, X-Forwarded-Ssl or X-Url-Scheme header,
  330. // will return https when a TLS connection is handled by the app, or http otherwise.
  331. // 2. c.IP() WON'T get value from ProxyHeader header, will return RemoteIP() from fasthttp context
  332. // 3. c.Host() and c.Hostname() WON'T get value from X-Forwarded-Host header, fasthttp.Request.URI().Host()
  333. // will be used to get the hostname.
  334. //
  335. // To automatically trust all loopback, link-local, or private IP addresses,
  336. // without manually adding them to the TrustProxyConfig.Proxies allowlist,
  337. // you can set TrustProxyConfig.Loopback, TrustProxyConfig.LinkLocal, or TrustProxyConfig.Private to true.
  338. //
  339. // Default: false
  340. TrustProxy bool `json:"trust_proxy"`
  341. // Read TrustProxy doc.
  342. //
  343. // Default: DefaultTrustProxyConfig
  344. TrustProxyConfig TrustProxyConfig `json:"trust_proxy_config"`
  345. // If set to true, c.IP() and c.IPs() will validate IP addresses before returning them.
  346. // Also, c.IP() will return only the first valid IP rather than just the raw header
  347. // WARNING: this has a performance cost associated with it.
  348. //
  349. // Default: false
  350. EnableIPValidation bool `json:"enable_ip_validation"`
  351. // You can define custom color scheme. They'll be used for startup message, route list and some middlewares.
  352. //
  353. // Optional. Default: DefaultColors
  354. ColorScheme Colors `json:"color_scheme"`
  355. // If you want to validate header/form/query... automatically when to bind, you can define struct validator.
  356. // Fiber doesn't have default validator, so it'll skip validator step if you don't use any validator.
  357. //
  358. // Default: nil
  359. StructValidator StructValidator
  360. // RequestMethods provides customizability for HTTP methods. You can add/remove methods as you wish.
  361. //
  362. // Optional. Default: DefaultMethods
  363. RequestMethods []string
  364. // EnableSplittingOnParsers splits the query/body/header parameters by comma when it's true.
  365. // For example, you can use it to parse multiple values from a query parameter like this:
  366. // /api?foo=bar,baz == foo[]=bar&foo[]=baz
  367. //
  368. // Optional. Default: false
  369. EnableSplittingOnParsers bool `json:"enable_splitting_on_parsers"`
  370. // Services is a list of services that are used by the app (e.g. databases, caches, etc.)
  371. //
  372. // Optional. Default: a zero value slice
  373. Services []Service
  374. // ServicesStartupContextProvider is a context provider for the startup of the services.
  375. //
  376. // Optional. Default: a provider that returns context.Background()
  377. ServicesStartupContextProvider func() context.Context
  378. // ServicesShutdownContextProvider is a context provider for the shutdown of the services.
  379. //
  380. // Optional. Default: a provider that returns context.Background()
  381. ServicesShutdownContextProvider func() context.Context
  382. }
  383. // Default TrustProxyConfig
  384. var DefaultTrustProxyConfig = TrustProxyConfig{}
  385. // TrustProxyConfig is a struct for configuring trusted proxies if Config.TrustProxy is true.
  386. type TrustProxyConfig struct {
  387. ips map[string]struct{}
  388. // Proxies is a list of trusted proxy IP addresses or CIDR ranges.
  389. //
  390. // Default: []string
  391. Proxies []string `json:"proxies"`
  392. ranges []*net.IPNet
  393. // LinkLocal enables trusting all link-local IP ranges (e.g., 169.254.0.0/16, fe80::/10).
  394. //
  395. // Default: false
  396. LinkLocal bool `json:"link_local"`
  397. // Loopback enables trusting all loopback IP ranges (e.g., 127.0.0.0/8, ::1/128).
  398. //
  399. // Default: false
  400. Loopback bool `json:"loopback"`
  401. // Private enables trusting all private IP ranges (e.g., 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, fc00::/7).
  402. //
  403. // Default: false
  404. Private bool `json:"private"`
  405. // UnixSocket enables trusting Unix domain socket connections.
  406. // When enabled, requests from Unix sockets are treated as trusted proxies.
  407. //
  408. // Default: false
  409. UnixSocket bool `json:"unix_socket"`
  410. }
  411. // RouteMessage is some message need to be print when server starts
  412. type RouteMessage struct {
  413. name string
  414. method string
  415. path string
  416. handlers string
  417. }
  418. // Default Config values
  419. const (
  420. DefaultBodyLimit = 4 * 1024 * 1024
  421. DefaultMaxRanges = 16
  422. DefaultConcurrency = 256 * 1024
  423. DefaultReadBufferSize = 4096
  424. DefaultWriteBufferSize = 4096
  425. )
  426. const (
  427. methodGet = iota
  428. methodHead
  429. methodPost
  430. methodPut
  431. methodDelete
  432. methodConnect
  433. methodOptions
  434. methodTrace
  435. methodPatch
  436. )
  437. // HTTP methods enabled by default
  438. var DefaultMethods = []string{
  439. methodGet: MethodGet,
  440. methodHead: MethodHead,
  441. methodPost: MethodPost,
  442. methodPut: MethodPut,
  443. methodDelete: MethodDelete,
  444. methodConnect: MethodConnect,
  445. methodOptions: MethodOptions,
  446. methodTrace: MethodTrace,
  447. methodPatch: MethodPatch,
  448. }
  449. // httpReadResponse - Used for test mocking http.ReadResponse
  450. var httpReadResponse = http.ReadResponse
  451. // DefaultErrorHandler that process return errors from handlers
  452. func DefaultErrorHandler(c Ctx, err error) error {
  453. code := StatusInternalServerError
  454. var e *Error
  455. if errors.As(err, &e) {
  456. code = e.Code
  457. }
  458. c.Set(HeaderContentType, MIMETextPlainCharsetUTF8)
  459. return c.Status(code).SendString(err.Error())
  460. }
  461. // New creates a new Fiber named instance.
  462. //
  463. // app := fiber.New()
  464. //
  465. // You can pass optional configuration options by passing a Config struct:
  466. //
  467. // app := fiber.New(fiber.Config{
  468. // ServerHeader: "Fiber",
  469. // })
  470. func New(config ...Config) *App {
  471. // Create a new app
  472. app := &App{
  473. // Create config
  474. config: Config{},
  475. toBytes: utils.UnsafeBytes,
  476. toString: utils.UnsafeString,
  477. latestRoute: &Route{},
  478. customBinders: []CustomBinder{},
  479. sendfiles: []*sendFileStore{},
  480. }
  481. // Create Ctx pool
  482. app.pool = sync.Pool{
  483. New: func() any {
  484. if app.newCtxFunc != nil {
  485. return app.newCtxFunc(app)
  486. }
  487. return NewDefaultCtx(app)
  488. },
  489. }
  490. // Define hooks
  491. app.hooks = newHooks(app)
  492. // Define mountFields
  493. app.mountFields = newMountFields(app)
  494. // Define state
  495. app.state = newState()
  496. // Override config if provided
  497. if len(config) > 0 {
  498. app.config = config[0]
  499. }
  500. // Initialize configured before defaults are set
  501. app.configured = app.config
  502. if err := app.validateConfiguredServices(); err != nil {
  503. panic(err)
  504. }
  505. // Override default values
  506. if app.config.BodyLimit <= 0 {
  507. app.config.BodyLimit = DefaultBodyLimit
  508. }
  509. if app.config.MaxRanges <= 0 {
  510. app.config.MaxRanges = DefaultMaxRanges
  511. }
  512. if app.config.Concurrency <= 0 {
  513. app.config.Concurrency = DefaultConcurrency
  514. }
  515. if app.config.ReadBufferSize <= 0 {
  516. app.config.ReadBufferSize = DefaultReadBufferSize
  517. }
  518. if app.config.WriteBufferSize <= 0 {
  519. app.config.WriteBufferSize = DefaultWriteBufferSize
  520. }
  521. if app.config.CompressedFileSuffixes == nil {
  522. app.config.CompressedFileSuffixes = map[string]string{
  523. "gzip": ".fiber.gz",
  524. "br": ".fiber.br",
  525. "zstd": ".fiber.zst",
  526. }
  527. }
  528. if app.config.Immutable {
  529. app.toBytes, app.toString = toBytesImmutable, toStringImmutable
  530. }
  531. if app.config.ErrorHandler == nil {
  532. app.config.ErrorHandler = DefaultErrorHandler
  533. }
  534. if app.config.JSONEncoder == nil {
  535. app.config.JSONEncoder = json.Marshal
  536. }
  537. if app.config.JSONDecoder == nil {
  538. app.config.JSONDecoder = json.Unmarshal
  539. }
  540. if app.config.MsgPackEncoder == nil {
  541. app.config.MsgPackEncoder = binder.UnimplementedMsgpackMarshal
  542. }
  543. if app.config.MsgPackDecoder == nil {
  544. app.config.MsgPackDecoder = binder.UnimplementedMsgpackUnmarshal
  545. }
  546. if app.config.CBOREncoder == nil {
  547. app.config.CBOREncoder = binder.UnimplementedCborMarshal
  548. }
  549. if app.config.CBORDecoder == nil {
  550. app.config.CBORDecoder = binder.UnimplementedCborUnmarshal
  551. }
  552. if app.config.XMLEncoder == nil {
  553. app.config.XMLEncoder = xml.Marshal
  554. }
  555. if app.config.XMLDecoder == nil {
  556. app.config.XMLDecoder = xml.Unmarshal
  557. }
  558. if len(app.config.RequestMethods) == 0 {
  559. app.config.RequestMethods = DefaultMethods
  560. }
  561. app.config.TrustProxyConfig.ips = make(map[string]struct{}, len(app.config.TrustProxyConfig.Proxies))
  562. for _, ipAddress := range app.config.TrustProxyConfig.Proxies {
  563. app.handleTrustedProxy(ipAddress)
  564. }
  565. // Create router stack
  566. app.stack = make([][]*Route, len(app.config.RequestMethods))
  567. app.treeStack = make([]map[int][]*Route, len(app.config.RequestMethods))
  568. // Override colors
  569. app.config.ColorScheme = defaultColors(&app.config.ColorScheme)
  570. // Init app
  571. app.init()
  572. // Return app
  573. return app
  574. }
  575. // NewWithCustomCtx creates a new Fiber instance and applies the
  576. // provided function to generate a custom context type. It mirrors the behavior
  577. // of calling `New()` followed by `app.setCtxFunc(fn)`.
  578. func NewWithCustomCtx(newCtxFunc func(app *App) CustomCtx, config ...Config) *App {
  579. app := New(config...)
  580. app.setCtxFunc(newCtxFunc)
  581. return app
  582. }
  583. // GetString returns s unchanged when Immutable is off or s is read-only (rodata).
  584. // Otherwise, it returns a detached copy (strings.Clone).
  585. func (app *App) GetString(s string) string {
  586. if !app.config.Immutable || s == "" {
  587. return s
  588. }
  589. if isReadOnly(unsafe.Pointer(unsafe.StringData(s))) { //nolint:gosec // pointer check avoids unnecessary copy
  590. return s // literal / rodata → safe to return as-is
  591. }
  592. return strings.Clone(s) // heap-backed / aliased → detach
  593. }
  594. // GetBytes returns b unchanged when Immutable is off or b is read-only (rodata).
  595. // Otherwise, it returns a detached copy.
  596. func (app *App) GetBytes(b []byte) []byte {
  597. if !app.config.Immutable || len(b) == 0 {
  598. return b
  599. }
  600. if isReadOnly(unsafe.Pointer(unsafe.SliceData(b))) { //nolint:gosec // pointer check avoids unnecessary copy
  601. return b // rodata → safe to return as-is
  602. }
  603. return utils.CopyBytes(b) // detach when backed by request/response memory
  604. }
  605. // Adds an ip address to TrustProxyConfig.ranges or TrustProxyConfig.ips based on whether it is an IP range or not
  606. func (app *App) handleTrustedProxy(ipAddress string) {
  607. if strings.IndexByte(ipAddress, '/') >= 0 {
  608. _, ipNet, err := net.ParseCIDR(ipAddress)
  609. if err != nil {
  610. log.Warnf("IP range %q could not be parsed: %v", ipAddress, err)
  611. } else {
  612. app.config.TrustProxyConfig.ranges = append(app.config.TrustProxyConfig.ranges, ipNet)
  613. }
  614. } else {
  615. ip := net.ParseIP(ipAddress)
  616. if ip == nil {
  617. log.Warnf("IP address %q could not be parsed", ipAddress)
  618. } else {
  619. app.config.TrustProxyConfig.ips[ipAddress] = struct{}{}
  620. }
  621. }
  622. }
  623. // setCtxFunc applies the given context factory to the app.
  624. // It is used internally by NewWithCustomCtx. It doesn't allow adding new methods,
  625. // only customizing existing ones.
  626. func (app *App) setCtxFunc(function func(app *App) CustomCtx) {
  627. app.newCtxFunc = function
  628. app.hasCustomCtx = function != nil
  629. if app.server != nil {
  630. app.server.Handler = app.requestHandler
  631. }
  632. }
  633. // RegisterCustomConstraint allows to register custom constraint.
  634. func (app *App) RegisterCustomConstraint(constraint CustomConstraint) {
  635. app.customConstraints = append(app.customConstraints, constraint)
  636. }
  637. // RegisterCustomBinder Allows to register custom binders to use as Bind().Custom("name").
  638. // They should be compatible with CustomBinder interface.
  639. func (app *App) RegisterCustomBinder(customBinder CustomBinder) {
  640. app.customBinders = append(app.customBinders, customBinder)
  641. }
  642. // ReloadViews reloads the configured view engine by invoking its Load method.
  643. // It returns an error if no view engine is configured or if reloading fails.
  644. func (app *App) ReloadViews() error {
  645. app.mutex.Lock()
  646. defer app.mutex.Unlock()
  647. apps := map[string]*App{"": app}
  648. if app.mountFields != nil {
  649. apps = app.mountFields.appList
  650. }
  651. var reloaded bool
  652. for _, targetApp := range apps {
  653. if targetApp == nil || targetApp.config.Views == nil {
  654. continue
  655. }
  656. if viewValue := reflect.ValueOf(targetApp.config.Views); viewValue.Kind() == reflect.Pointer && viewValue.IsNil() {
  657. continue
  658. }
  659. if err := targetApp.config.Views.Load(); err != nil {
  660. return fmt.Errorf("fiber: failed to reload views: %w", err)
  661. }
  662. reloaded = true
  663. }
  664. if !reloaded {
  665. return ErrNoViewEngineConfigured
  666. }
  667. return nil
  668. }
  669. // SetTLSHandler Can be used to set ClientHelloInfo when using TLS with Listener.
  670. func (app *App) SetTLSHandler(tlsHandler *TLSHandler) {
  671. // Attach the tlsHandler to the config
  672. app.mutex.Lock()
  673. app.tlsHandler = tlsHandler
  674. app.mutex.Unlock()
  675. }
  676. // Name Assign name to specific route.
  677. func (app *App) Name(name string) Router {
  678. app.mutex.Lock()
  679. defer app.mutex.Unlock()
  680. for _, routes := range app.stack {
  681. for _, route := range routes {
  682. isMethodValid := route.Method == app.latestRoute.Method || app.latestRoute.use ||
  683. (app.latestRoute.Method == MethodGet && route.Method == MethodHead)
  684. if route.Path == app.latestRoute.Path && isMethodValid {
  685. route.Name = name
  686. if route.group != nil {
  687. route.Name = route.group.name + route.Name
  688. }
  689. }
  690. }
  691. }
  692. if err := app.hooks.executeOnNameHooks(app.latestRoute); err != nil {
  693. panic(err)
  694. }
  695. return app
  696. }
  697. // GetRoute Get route by name
  698. func (app *App) GetRoute(name string) Route {
  699. for _, routes := range app.stack {
  700. for _, route := range routes {
  701. if route.Name == name {
  702. return *route
  703. }
  704. }
  705. }
  706. return Route{}
  707. }
  708. // GetRoutes Get all routes. When filterUseOption equal to true, it will filter the routes registered by the middleware.
  709. func (app *App) GetRoutes(filterUseOption ...bool) []Route {
  710. var rs []Route
  711. var filterUse bool
  712. if len(filterUseOption) != 0 {
  713. filterUse = filterUseOption[0]
  714. }
  715. for _, routes := range app.stack {
  716. for _, route := range routes {
  717. if filterUse && route.use {
  718. continue
  719. }
  720. rs = append(rs, *route)
  721. }
  722. }
  723. return rs
  724. }
  725. // Use registers a middleware route that will match requests
  726. // with the provided prefix (which is optional and defaults to "/").
  727. // Also, you can pass another app instance as a sub-router along a routing path.
  728. // It's very useful to split up a large API as many independent routers and
  729. // compose them as a single service using Use. The fiber's error handler and
  730. // any of the fiber's sub apps are added to the application's error handlers
  731. // to be invoked on errors that happen within the prefix route.
  732. //
  733. // app.Use(func(c fiber.Ctx) error {
  734. // return c.Next()
  735. // })
  736. // app.Use("/api", func(c fiber.Ctx) error {
  737. // return c.Next()
  738. // })
  739. // app.Use("/api", handler, func(c fiber.Ctx) error {
  740. // return c.Next()
  741. // })
  742. // subApp := fiber.New()
  743. // app.Use("/mounted-path", subApp)
  744. //
  745. // This method will match all HTTP verbs: GET, POST, PUT, HEAD etc...
  746. func (app *App) Use(args ...any) Router {
  747. var prefix string
  748. var subApp *App
  749. var prefixes []string
  750. var handlers []Handler
  751. for i := range args {
  752. switch arg := args[i].(type) {
  753. case string:
  754. prefix = arg
  755. case *App:
  756. subApp = arg
  757. case []string:
  758. prefixes = arg
  759. default:
  760. handler, ok := toFiberHandler(arg)
  761. if !ok {
  762. panic(fmt.Sprintf("use: invalid handler %v\n", reflect.TypeOf(arg)))
  763. }
  764. handlers = append(handlers, handler)
  765. }
  766. }
  767. if len(prefixes) == 0 {
  768. prefixes = append(prefixes, prefix)
  769. }
  770. for _, prefix := range prefixes {
  771. if subApp != nil {
  772. return app.mount(prefix, subApp)
  773. }
  774. app.register([]string{methodUse}, prefix, nil, handlers...)
  775. }
  776. return app
  777. }
  778. // Get registers a route for GET methods that requests a representation
  779. // of the specified resource. Requests using GET should only retrieve data.
  780. func (app *App) Get(path string, handler any, handlers ...any) Router {
  781. return app.Add([]string{MethodGet}, path, handler, handlers...)
  782. }
  783. // Head registers a route for HEAD methods that asks for a response identical
  784. // to that of a GET request, but without the response body.
  785. func (app *App) Head(path string, handler any, handlers ...any) Router {
  786. return app.Add([]string{MethodHead}, path, handler, handlers...)
  787. }
  788. // Post registers a route for POST methods that is used to submit an entity to the
  789. // specified resource, often causing a change in state or side effects on the server.
  790. func (app *App) Post(path string, handler any, handlers ...any) Router {
  791. return app.Add([]string{MethodPost}, path, handler, handlers...)
  792. }
  793. // Put registers a route for PUT methods that replaces all current representations
  794. // of the target resource with the request payload.
  795. func (app *App) Put(path string, handler any, handlers ...any) Router {
  796. return app.Add([]string{MethodPut}, path, handler, handlers...)
  797. }
  798. // Delete registers a route for DELETE methods that deletes the specified resource.
  799. func (app *App) Delete(path string, handler any, handlers ...any) Router {
  800. return app.Add([]string{MethodDelete}, path, handler, handlers...)
  801. }
  802. // Connect registers a route for CONNECT methods that establishes a tunnel to the
  803. // server identified by the target resource.
  804. func (app *App) Connect(path string, handler any, handlers ...any) Router {
  805. return app.Add([]string{MethodConnect}, path, handler, handlers...)
  806. }
  807. // Options registers a route for OPTIONS methods that is used to describe the
  808. // communication options for the target resource.
  809. func (app *App) Options(path string, handler any, handlers ...any) Router {
  810. return app.Add([]string{MethodOptions}, path, handler, handlers...)
  811. }
  812. // Trace registers a route for TRACE methods that performs a message loop-back
  813. // test along the path to the target resource.
  814. func (app *App) Trace(path string, handler any, handlers ...any) Router {
  815. return app.Add([]string{MethodTrace}, path, handler, handlers...)
  816. }
  817. // Patch registers a route for PATCH methods that is used to apply partial
  818. // modifications to a resource.
  819. func (app *App) Patch(path string, handler any, handlers ...any) Router {
  820. return app.Add([]string{MethodPatch}, path, handler, handlers...)
  821. }
  822. // Add allows you to specify multiple HTTP methods to register a route.
  823. // The provided handlers are executed in order, starting with `handler` and then the variadic `handlers`.
  824. func (app *App) Add(methods []string, path string, handler any, handlers ...any) Router {
  825. converted := collectHandlers("add", append([]any{handler}, handlers...)...)
  826. app.register(methods, path, nil, converted...)
  827. return app
  828. }
  829. // All will register the handler on all HTTP methods
  830. func (app *App) All(path string, handler any, handlers ...any) Router {
  831. return app.Add(app.config.RequestMethods, path, handler, handlers...)
  832. }
  833. // Group is used for Routes with common prefix to define a new sub-router with optional middleware.
  834. //
  835. // api := app.Group("/api")
  836. // api.Get("/users", handler)
  837. func (app *App) Group(prefix string, handlers ...any) Router {
  838. grp := &Group{Prefix: prefix, app: app}
  839. if len(handlers) > 0 {
  840. converted := collectHandlers("group", handlers...)
  841. app.register([]string{methodUse}, prefix, grp, converted...)
  842. }
  843. if err := app.hooks.executeOnGroupHooks(*grp); err != nil {
  844. panic(err)
  845. }
  846. return grp
  847. }
  848. // RouteChain creates a Registering instance that lets you declare a stack of
  849. // handlers for the same route. Handlers defined via the returned Register are
  850. // scoped to the provided path.
  851. func (app *App) RouteChain(path string) Register {
  852. // Create new route
  853. route := &Registering{app: app, path: path}
  854. return route
  855. }
  856. // Route is used to define routes with a common prefix inside the supplied
  857. // function. It mirrors the legacy helper and reuses the Group method to create
  858. // a sub-router.
  859. func (app *App) Route(prefix string, fn func(router Router), name ...string) Router {
  860. if fn == nil {
  861. panic("route handler 'fn' cannot be nil")
  862. }
  863. // Create new group
  864. group := app.Group(prefix)
  865. if len(name) > 0 {
  866. group.Name(name[0])
  867. }
  868. // Define routes
  869. fn(group)
  870. return group
  871. }
  872. // Error makes it compatible with the `error` interface.
  873. func (e *Error) Error() string {
  874. return e.Message
  875. }
  876. // NewError creates a new Error instance with an optional message
  877. func NewError(code int, message ...string) *Error {
  878. err := &Error{
  879. Code: code,
  880. Message: utils.StatusMessage(code),
  881. }
  882. if len(message) > 0 {
  883. err.Message = message[0]
  884. }
  885. return err
  886. }
  887. // NewErrorf creates a new Error instance with an optional message.
  888. // Additional arguments are formatted using fmt.Sprintf when provided.
  889. // If the first argument in the message slice is not a string, the function
  890. // falls back to using fmt.Sprint on the first element to generate the message.
  891. func NewErrorf(code int, message ...any) *Error {
  892. var msg string
  893. switch len(message) {
  894. case 0:
  895. // nothing to override
  896. msg = utils.StatusMessage(code)
  897. case 1:
  898. // One argument → treat it like fmt.Sprint(arg)
  899. if s, ok := message[0].(string); ok {
  900. msg = s
  901. } else {
  902. msg = fmt.Sprint(message[0])
  903. }
  904. default:
  905. // Two or more → first must be a format string.
  906. if format, ok := message[0].(string); ok {
  907. msg = fmt.Sprintf(format, message[1:]...)
  908. } else {
  909. // If the first arg isn’t a string, fall back.
  910. msg = fmt.Sprint(message[0])
  911. }
  912. }
  913. return &Error{Code: code, Message: msg}
  914. }
  915. // Config returns the app config as value ( read-only ).
  916. func (app *App) Config() Config {
  917. return app.config
  918. }
  919. // Handler returns the server handler.
  920. 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
  921. // prepare the server for the start
  922. app.startupProcess()
  923. return app.requestHandler
  924. }
  925. // Stack returns the raw router stack.
  926. func (app *App) Stack() [][]*Route {
  927. return app.stack
  928. }
  929. // HandlersCount returns the amount of registered handlers.
  930. func (app *App) HandlersCount() uint32 {
  931. return app.handlersCount
  932. }
  933. // Shutdown gracefully shuts down the server without interrupting any active connections.
  934. // Shutdown works by first closing all open listeners and then waiting indefinitely for all connections to return to idle before shutting down.
  935. //
  936. // Make sure the program doesn't exit and waits instead for Shutdown to return.
  937. //
  938. // Important: app.Listen() must be called in a separate goroutine; otherwise, shutdown hooks will not work
  939. // as Listen() is a blocking operation. Example:
  940. //
  941. // go app.Listen(":3000")
  942. // // ...
  943. // app.Shutdown()
  944. //
  945. // Shutdown does not close keepalive connections so its recommended to set ReadTimeout to something else than 0.
  946. func (app *App) Shutdown() error {
  947. return app.ShutdownWithContext(context.Background())
  948. }
  949. // ShutdownWithTimeout gracefully shuts down the server without interrupting any active connections. However, if the timeout is exceeded,
  950. // ShutdownWithTimeout will forcefully close any active connections.
  951. // ShutdownWithTimeout works by first closing all open listeners and then waiting for all connections to return to idle before shutting down.
  952. //
  953. // Make sure the program doesn't exit and waits instead for ShutdownWithTimeout to return.
  954. //
  955. // ShutdownWithTimeout does not close keepalive connections so its recommended to set ReadTimeout to something else than 0.
  956. func (app *App) ShutdownWithTimeout(timeout time.Duration) error {
  957. ctx, cancelFunc := context.WithTimeout(context.Background(), timeout)
  958. defer cancelFunc()
  959. return app.ShutdownWithContext(ctx)
  960. }
  961. // ShutdownWithContext shuts down the server including by force if the context's deadline is exceeded.
  962. //
  963. // Make sure the program doesn't exit and waits instead for ShutdownWithTimeout to return.
  964. //
  965. // ShutdownWithContext does not close keepalive connections so its recommended to set ReadTimeout to something else than 0.
  966. func (app *App) ShutdownWithContext(ctx context.Context) error {
  967. app.mutex.Lock()
  968. defer app.mutex.Unlock()
  969. var err error
  970. if app.server == nil {
  971. return ErrNotRunning
  972. }
  973. // Execute the Shutdown hook
  974. app.hooks.executeOnPreShutdownHooks()
  975. defer app.hooks.executeOnPostShutdownHooks(err)
  976. err = app.server.ShutdownWithContext(ctx)
  977. return err
  978. }
  979. // Server returns the underlying fasthttp server
  980. func (app *App) Server() *fasthttp.Server {
  981. return app.server
  982. }
  983. // Hooks returns the hook struct to register hooks.
  984. func (app *App) Hooks() *Hooks {
  985. return app.hooks
  986. }
  987. // State returns the state struct to store global data in order to share it between handlers.
  988. func (app *App) State() *State {
  989. return app.state
  990. }
  991. var ErrTestGotEmptyResponse = errors.New("test: got empty response")
  992. // TestConfig is a struct holding Test settings
  993. type TestConfig struct {
  994. // Timeout defines the maximum duration a
  995. // test can run before timing out.
  996. // Default: time.Second
  997. Timeout time.Duration
  998. // FailOnTimeout specifies whether the test
  999. // should return a timeout error if the HTTP response
  1000. // exceeds the Timeout duration.
  1001. // Default: true
  1002. FailOnTimeout bool
  1003. }
  1004. // Test is used for internal debugging by passing a *http.Request.
  1005. // Config is optional and defaults to a 1s error on timeout,
  1006. // 0 timeout will disable it completely.
  1007. func (app *App) Test(req *http.Request, config ...TestConfig) (*http.Response, error) {
  1008. // Default config
  1009. cfg := TestConfig{
  1010. Timeout: time.Second,
  1011. FailOnTimeout: true,
  1012. }
  1013. // Override config if provided
  1014. if len(config) > 0 {
  1015. cfg = config[0]
  1016. }
  1017. // Add Content-Length if not provided with body
  1018. if req.Body != http.NoBody && req.Header.Get(HeaderContentLength) == "" {
  1019. req.Header.Add(HeaderContentLength, strconv.FormatInt(req.ContentLength, 10))
  1020. }
  1021. // Dump raw http request
  1022. dump, err := httputil.DumpRequest(req, true)
  1023. if err != nil {
  1024. return nil, fmt.Errorf("failed to dump request: %w", err)
  1025. }
  1026. // Create test connection
  1027. conn := new(testConn)
  1028. // Write raw http request
  1029. if _, err = conn.r.Write(dump); err != nil {
  1030. return nil, fmt.Errorf("failed to write: %w", err)
  1031. }
  1032. // prepare the server for the start
  1033. app.startupProcess()
  1034. // Serve conn to server
  1035. channel := make(chan error, 1)
  1036. go func() {
  1037. var returned bool
  1038. defer func() {
  1039. if !returned {
  1040. channel <- ErrHandlerExited
  1041. }
  1042. }()
  1043. channel <- app.server.ServeConn(conn)
  1044. returned = true
  1045. }()
  1046. // Wait for callback
  1047. if cfg.Timeout > 0 {
  1048. // With timeout
  1049. select {
  1050. case err = <-channel:
  1051. case <-time.After(cfg.Timeout):
  1052. if cfg.FailOnTimeout {
  1053. conn.Close() //nolint:errcheck // It is fine to ignore the error here
  1054. return nil, os.ErrDeadlineExceeded
  1055. }
  1056. // When FailOnTimeout is false, wait up to 1 additional second for the handler
  1057. // to complete and write a response. This prevents indefinite blocking while
  1058. // allowing slow handlers to finish.
  1059. select {
  1060. case err = <-channel:
  1061. case <-time.After(time.Second):
  1062. // Handler took too long even with extra time
  1063. conn.Close() //nolint:errcheck // It is fine to ignore the error here
  1064. }
  1065. }
  1066. } else {
  1067. // Without timeout
  1068. err = <-channel
  1069. }
  1070. // Check for errors
  1071. if err != nil && !errors.Is(err, fasthttp.ErrGetOnly) && !errors.Is(err, errTestConnClosed) {
  1072. return nil, err
  1073. }
  1074. // Read response(s)
  1075. buffer := bufio.NewReader(&conn.w)
  1076. var res *http.Response
  1077. for {
  1078. // Convert raw http response to *http.Response
  1079. res, err = httpReadResponse(buffer, req)
  1080. if err != nil {
  1081. if errors.Is(err, io.ErrUnexpectedEOF) {
  1082. return nil, ErrTestGotEmptyResponse
  1083. }
  1084. return nil, fmt.Errorf("failed to read response: %w", err)
  1085. }
  1086. // Break if this response is non-1xx or there are no more responses
  1087. if res.StatusCode >= http.StatusOK || buffer.Buffered() == 0 {
  1088. break
  1089. }
  1090. // Discard interim response body before reading the next one
  1091. if res.Body != nil {
  1092. if _, errCopy := io.Copy(io.Discard, res.Body); errCopy != nil {
  1093. return nil, fmt.Errorf("failed to discard interim response body: %w", errCopy)
  1094. }
  1095. if errClose := res.Body.Close(); errClose != nil {
  1096. return nil, fmt.Errorf("failed to close interim response body: %w", errClose)
  1097. }
  1098. }
  1099. }
  1100. return res, nil
  1101. }
  1102. type disableLogger struct{}
  1103. // Printf implements the fasthttp Logger interface and discards log output.
  1104. func (*disableLogger) Printf(string, ...any) {
  1105. }
  1106. func (app *App) init() *App {
  1107. // lock application
  1108. app.mutex.Lock()
  1109. // Initialize Services when needed,
  1110. // panics if there is an error starting them.
  1111. app.initServices()
  1112. // Only load templates if a view engine is specified
  1113. if app.config.Views != nil {
  1114. if err := app.config.Views.Load(); err != nil {
  1115. log.Warnf("failed to load views: %v", err)
  1116. }
  1117. }
  1118. // create fasthttp server
  1119. app.server = &fasthttp.Server{
  1120. Logger: &disableLogger{},
  1121. LogAllErrors: false,
  1122. ErrorHandler: app.serverErrorHandler,
  1123. }
  1124. // fasthttp server settings
  1125. app.server.Handler = app.requestHandler
  1126. app.server.Name = app.config.ServerHeader
  1127. app.server.Concurrency = app.config.Concurrency
  1128. app.server.NoDefaultDate = app.config.DisableDefaultDate
  1129. app.server.NoDefaultContentType = app.config.DisableDefaultContentType
  1130. app.server.DisableHeaderNamesNormalizing = app.config.DisableHeaderNormalizing
  1131. app.server.DisableKeepalive = app.config.DisableKeepalive
  1132. app.server.MaxRequestBodySize = app.config.BodyLimit
  1133. app.server.NoDefaultServerHeader = app.config.ServerHeader == ""
  1134. app.server.ReadTimeout = app.config.ReadTimeout
  1135. app.server.WriteTimeout = app.config.WriteTimeout
  1136. app.server.IdleTimeout = app.config.IdleTimeout
  1137. app.server.ReadBufferSize = app.config.ReadBufferSize
  1138. app.server.WriteBufferSize = app.config.WriteBufferSize
  1139. app.server.GetOnly = app.config.GETOnly
  1140. app.server.ReduceMemoryUsage = app.config.ReduceMemoryUsage
  1141. app.server.StreamRequestBody = app.config.StreamRequestBody
  1142. app.server.DisablePreParseMultipartForm = app.config.DisablePreParseMultipartForm
  1143. // unlock application
  1144. app.mutex.Unlock()
  1145. // Register the Services shutdown handler once the app is initialized and unlocked.
  1146. app.Hooks().OnPostShutdown(func(_ error) error {
  1147. if err := app.shutdownServices(app.servicesShutdownCtx()); err != nil {
  1148. log.Errorf("failed to shutdown services: %v", err)
  1149. }
  1150. return nil
  1151. })
  1152. return app
  1153. }
  1154. // ErrorHandler is the application's method in charge of finding the
  1155. // appropriate handler for the given request. It searches any mounted
  1156. // sub fibers by their prefixes and if it finds a match, it uses that
  1157. // error handler. Otherwise, it uses the configured error handler for
  1158. // the app, which if not set is the DefaultErrorHandler.
  1159. func (app *App) ErrorHandler(ctx Ctx, err error) error {
  1160. var (
  1161. mountedErrHandler ErrorHandler
  1162. mountedPrefixParts int
  1163. )
  1164. normalizedPath := utils.AddTrailingSlashString(ctx.Path())
  1165. for _, prefix := range app.mountFields.appListKeys {
  1166. subApp := app.mountFields.appList[prefix]
  1167. normalizedPrefix := utils.AddTrailingSlashString(prefix)
  1168. if prefix != "" && strings.HasPrefix(normalizedPath, normalizedPrefix) {
  1169. // Count slashes instead of splitting - more efficient
  1170. parts := strings.Count(prefix, "/") + 1
  1171. if mountedPrefixParts <= parts {
  1172. if subApp.configured.ErrorHandler != nil {
  1173. mountedErrHandler = subApp.config.ErrorHandler
  1174. }
  1175. mountedPrefixParts = parts
  1176. }
  1177. }
  1178. }
  1179. if mountedErrHandler != nil {
  1180. return mountedErrHandler(ctx, err)
  1181. }
  1182. return app.config.ErrorHandler(ctx, err)
  1183. }
  1184. // serverErrorHandler is a wrapper around the application's error handler method
  1185. // user for the fasthttp server configuration. It maps a set of fasthttp errors to fiber
  1186. // errors before calling the application's error handler method.
  1187. func (app *App) serverErrorHandler(fctx *fasthttp.RequestCtx, err error) {
  1188. // Acquire Ctx with fasthttp request from pool
  1189. c := app.AcquireCtx(fctx)
  1190. defer app.ReleaseCtx(c)
  1191. var (
  1192. errNetOP *net.OpError
  1193. netErr net.Error
  1194. )
  1195. switch {
  1196. case errors.As(err, new(*fasthttp.ErrSmallBuffer)):
  1197. err = ErrRequestHeaderFieldsTooLarge
  1198. case errors.As(err, &errNetOP) && errNetOP.Timeout():
  1199. err = ErrRequestTimeout
  1200. case errors.As(err, &netErr):
  1201. err = ErrBadGateway
  1202. case errors.Is(err, fasthttp.ErrBodyTooLarge):
  1203. err = ErrRequestEntityTooLarge
  1204. case errors.Is(err, fasthttp.ErrGetOnly):
  1205. err = ErrMethodNotAllowed
  1206. case strings.Contains(err.Error(), "unsupported http request method"):
  1207. err = ErrNotImplemented
  1208. case strings.Contains(err.Error(), "timeout"):
  1209. err = ErrRequestTimeout
  1210. default:
  1211. err = NewError(StatusBadRequest, err.Error())
  1212. }
  1213. if c.getMethodInt() != -1 {
  1214. c.setSkipNonUseRoutes(true)
  1215. defer c.setSkipNonUseRoutes(false)
  1216. var nextErr error
  1217. if d, isDefault := c.(*DefaultCtx); isDefault {
  1218. _, nextErr = app.next(d)
  1219. } else {
  1220. _, nextErr = app.nextCustom(c)
  1221. }
  1222. if nextErr != nil && !errors.Is(nextErr, ErrNotFound) && !errors.Is(nextErr, ErrMethodNotAllowed) {
  1223. log.Errorf("serverErrorHandler: middleware traversal failed: %v", nextErr)
  1224. }
  1225. }
  1226. if catch := app.ErrorHandler(c, err); catch != nil {
  1227. log.Errorf("serverErrorHandler: failed to call ErrorHandler: %v", catch)
  1228. _ = c.SendStatus(StatusInternalServerError) //nolint:errcheck // It is fine to ignore the error here
  1229. return
  1230. }
  1231. }
  1232. // startupProcess Is the method which executes all the necessary processes just before the start of the server.
  1233. func (app *App) startupProcess() {
  1234. app.mutex.Lock()
  1235. defer app.mutex.Unlock()
  1236. app.ensureAutoHeadRoutesLocked()
  1237. for prefix, subApp := range app.mountFields.appList {
  1238. if prefix == "" {
  1239. continue
  1240. }
  1241. subApp.ensureAutoHeadRoutes()
  1242. }
  1243. app.mountStartupProcess()
  1244. // build route tree stack
  1245. app.buildTree()
  1246. }
  1247. // Run onListen hooks. If they return an error, panic.
  1248. func (app *App) runOnListenHooks(listenData *ListenData) {
  1249. if err := app.hooks.executeOnListenHooks(listenData); err != nil {
  1250. panic(err)
  1251. }
  1252. }