req.go 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173
  1. package fiber
  2. import (
  3. "bytes"
  4. "errors"
  5. "fmt"
  6. "math"
  7. "mime/multipart"
  8. "net"
  9. "strconv"
  10. "strings"
  11. "github.com/gofiber/utils/v2"
  12. utilsbytes "github.com/gofiber/utils/v2/bytes"
  13. utilsstrings "github.com/gofiber/utils/v2/strings"
  14. "github.com/valyala/bytebufferpool"
  15. "github.com/valyala/fasthttp"
  16. "golang.org/x/net/idna"
  17. )
  18. // Pre-allocated byte slices for common header comparisons to avoid allocations
  19. var (
  20. xForwardedPrefix = []byte("X-Forwarded-")
  21. xForwardedProtoBytes = []byte(HeaderXForwardedProto)
  22. xForwardedProtocolBytes = []byte(HeaderXForwardedProtocol)
  23. xForwardedSslBytes = []byte(HeaderXForwardedSsl)
  24. xURLSchemeBytes = []byte(HeaderXUrlScheme)
  25. onBytes = []byte("on")
  26. )
  27. // Range represents the parsed HTTP Range header extracted by DefaultReq.Range.
  28. type Range struct {
  29. Type string
  30. Ranges []RangeSet
  31. }
  32. // RangeSet represents a single content range from a request.
  33. type RangeSet struct {
  34. Start int64
  35. End int64
  36. }
  37. // DefaultReq is the default implementation of Req used by DefaultCtx.
  38. //
  39. //go:generate ifacemaker --file req.go --struct DefaultReq --iface Req --pkg fiber --output req_interface_gen.go --not-exported true --iface-comment "Req is an interface for request-related Ctx methods."
  40. type DefaultReq struct {
  41. c *DefaultCtx
  42. }
  43. // Accepts checks if the specified extensions or content types are acceptable.
  44. func (r *DefaultReq) Accepts(offers ...string) string {
  45. header := joinHeaderValues(r.c.fasthttp.Request.Header.PeekAll(HeaderAccept))
  46. return getOffer(header, acceptsOfferType, offers...)
  47. }
  48. // AcceptsCharsets checks if the specified charset is acceptable.
  49. func (r *DefaultReq) AcceptsCharsets(offers ...string) string {
  50. header := joinHeaderValues(r.c.fasthttp.Request.Header.PeekAll(HeaderAcceptCharset))
  51. return getOffer(header, acceptsOffer, offers...)
  52. }
  53. // AcceptsEncodings checks if the specified encoding is acceptable.
  54. func (r *DefaultReq) AcceptsEncodings(offers ...string) string {
  55. header := joinHeaderValues(r.c.fasthttp.Request.Header.PeekAll(HeaderAcceptEncoding))
  56. return getOffer(header, acceptsOffer, offers...)
  57. }
  58. // AcceptsLanguages checks if the specified language is acceptable using
  59. // RFC 4647 Basic Filtering.
  60. func (r *DefaultReq) AcceptsLanguages(offers ...string) string {
  61. header := joinHeaderValues(r.c.fasthttp.Request.Header.PeekAll(HeaderAcceptLanguage))
  62. return getOffer(header, acceptsLanguageOfferBasic, offers...)
  63. }
  64. // AcceptsLanguagesExtended checks if the specified language is acceptable using
  65. // RFC 4647 Extended Filtering.
  66. func (r *DefaultReq) AcceptsLanguagesExtended(offers ...string) string {
  67. header := joinHeaderValues(r.c.fasthttp.Request.Header.PeekAll(HeaderAcceptLanguage))
  68. return getOffer(header, acceptsLanguageOfferExtended, offers...)
  69. }
  70. // App returns the *App reference to the instance of the Fiber application
  71. func (r *DefaultReq) App() *App {
  72. return r.c.app
  73. }
  74. // BaseURL returns (protocol + host + base path).
  75. func (r *DefaultReq) BaseURL() string {
  76. return r.c.BaseURL()
  77. }
  78. // BodyRaw contains the raw body submitted in a POST request.
  79. // Returned value is only valid within the handler. Do not store any references.
  80. // Make copies or use the Immutable setting instead.
  81. func (r *DefaultReq) BodyRaw() []byte {
  82. return r.getBody()
  83. }
  84. //nolint:nonamedreturns // gocritic unnamedResult prefers naming decoded body, decode count, and error
  85. func (r *DefaultReq) tryDecodeBodyInOrder(
  86. originalBody *[]byte,
  87. encodings []string,
  88. ) (body []byte, decodesRealized uint8, err error) {
  89. request := &r.c.fasthttp.Request
  90. maxBodySize := r.c.app.config.BodyLimit
  91. for idx := range encodings {
  92. i := len(encodings) - 1 - idx
  93. encoding := encodings[i]
  94. decodesRealized++
  95. var decodeErr error
  96. switch encoding {
  97. case StrGzip, "x-gzip":
  98. body, decodeErr = request.BodyGunzipWithLimit(maxBodySize)
  99. case StrBr, StrBrotli:
  100. body, decodeErr = request.BodyUnbrotliWithLimit(maxBodySize)
  101. case StrDeflate:
  102. body, decodeErr = request.BodyInflateWithLimit(maxBodySize)
  103. case StrZstd:
  104. body, decodeErr = request.BodyUnzstdWithLimit(maxBodySize)
  105. case StrIdentity:
  106. body = request.Body()
  107. case StrCompress, "x-compress":
  108. return nil, decodesRealized - 1, ErrNotImplemented
  109. default:
  110. return nil, decodesRealized - 1, ErrUnsupportedMediaType
  111. }
  112. if decodeErr != nil {
  113. return nil, decodesRealized, decodeErr
  114. }
  115. if i > 0 && decodesRealized > 0 {
  116. if i == len(encodings)-1 {
  117. tempBody := request.Body()
  118. *originalBody = make([]byte, len(tempBody))
  119. copy(*originalBody, tempBody)
  120. }
  121. request.SetBodyRaw(body)
  122. }
  123. }
  124. return body, decodesRealized, nil
  125. }
  126. // Body contains the raw body submitted in a POST request.
  127. // This method will decompress the body if the 'Content-Encoding' header is provided.
  128. // It returns the original (or decompressed) body data which is valid only within the handler.
  129. // Don't store direct references to the returned data.
  130. // If you need to keep the body's data later, make a copy or use the Immutable option.
  131. func (r *DefaultReq) Body() []byte {
  132. var (
  133. err error
  134. body, originalBody []byte
  135. headerEncoding string
  136. encodingOrder = []string{"", "", ""}
  137. )
  138. request := &r.c.fasthttp.Request
  139. // Get Content-Encoding header
  140. headerEncoding = utils.UnsafeString(utilsbytes.UnsafeToLower(request.Header.ContentEncoding()))
  141. // If no encoding is provided, return the original body
  142. if headerEncoding == "" {
  143. return r.getBody()
  144. }
  145. // Split and get the encodings list, in order to attend the
  146. // rule defined at: https://www.rfc-editor.org/rfc/rfc9110#section-8.4-5
  147. encodingOrder = getSplicedStrList(headerEncoding, encodingOrder)
  148. for i := range encodingOrder {
  149. encodingOrder[i] = utilsstrings.UnsafeToLower(encodingOrder[i])
  150. }
  151. if len(encodingOrder) == 0 {
  152. return r.getBody()
  153. }
  154. var decodesRealized uint8
  155. body, decodesRealized, err = r.tryDecodeBodyInOrder(&originalBody, encodingOrder)
  156. // Ensure that the body will be the original
  157. if originalBody != nil && decodesRealized > 0 {
  158. request.SetBodyRaw(originalBody)
  159. }
  160. if err != nil {
  161. switch {
  162. case errors.Is(err, ErrUnsupportedMediaType):
  163. _ = r.c.DefaultRes.SendStatus(StatusUnsupportedMediaType) //nolint:errcheck,staticcheck // It is fine to ignore the error and the static check
  164. case errors.Is(err, ErrNotImplemented):
  165. _ = r.c.DefaultRes.SendStatus(StatusNotImplemented) //nolint:errcheck,staticcheck // It is fine to ignore the error and the static check
  166. case errors.Is(err, fasthttp.ErrBodyTooLarge):
  167. _ = r.c.DefaultRes.SendStatus(StatusRequestEntityTooLarge) //nolint:errcheck,staticcheck // It is fine to ignore the error and the static check
  168. default:
  169. // do nothing
  170. }
  171. return []byte(err.Error())
  172. }
  173. return r.c.app.GetBytes(body)
  174. }
  175. // RequestCtx returns *fasthttp.RequestCtx that carries a deadline
  176. // a cancellation signal, and other values across API boundaries.
  177. func (r *DefaultReq) RequestCtx() *fasthttp.RequestCtx {
  178. return r.c.fasthttp
  179. }
  180. // FullURL returns the full request URL (protocol + host + original URL).
  181. func (c *DefaultCtx) FullURL() string {
  182. buf := bytebufferpool.Get()
  183. defer bytebufferpool.Put(buf)
  184. buf.WriteString(c.Scheme())
  185. buf.WriteString("://")
  186. buf.WriteString(c.Host())
  187. buf.WriteString(c.OriginalURL())
  188. return c.app.toString(buf.Bytes())
  189. }
  190. // UserAgent returns the User-Agent request header.
  191. func (c *DefaultCtx) UserAgent() string {
  192. return c.app.toString(c.fasthttp.Request.Header.UserAgent())
  193. }
  194. // Referer returns the Referer request header.
  195. func (c *DefaultCtx) Referer() string {
  196. return c.app.toString(c.fasthttp.Request.Header.Referer())
  197. }
  198. // AcceptLanguage returns the Accept-Language request header.
  199. func (c *DefaultCtx) AcceptLanguage() string {
  200. return c.app.toString(c.fasthttp.Request.Header.Peek(HeaderAcceptLanguage))
  201. }
  202. // AcceptEncoding returns the Accept-Encoding request header.
  203. func (c *DefaultCtx) AcceptEncoding() string {
  204. return c.app.toString(c.fasthttp.Request.Header.Peek(HeaderAcceptEncoding))
  205. }
  206. // HasHeader reports whether the request includes a header with the given key.
  207. func (c *DefaultCtx) HasHeader(key string) bool {
  208. return len(c.fasthttp.Request.Header.Peek(key)) > 0
  209. }
  210. // MediaType returns the MIME type from the Content-Type header without parameters.
  211. func (c *DefaultCtx) MediaType() string {
  212. contentType := utils.TrimSpace(c.fasthttp.Request.Header.ContentType())
  213. if len(contentType) == 0 {
  214. return ""
  215. }
  216. if idx := bytes.IndexByte(contentType, ';'); idx != -1 {
  217. contentType = contentType[:idx]
  218. }
  219. contentType = utils.TrimSpace(contentType)
  220. return c.app.toString(contentType)
  221. }
  222. // Charset returns the charset parameter from the Content-Type header.
  223. func (c *DefaultCtx) Charset() string {
  224. contentType := c.fasthttp.Request.Header.ContentType()
  225. if len(contentType) == 0 {
  226. return ""
  227. }
  228. _, after, ok := bytes.Cut(contentType, []byte{';'})
  229. if !ok {
  230. return ""
  231. }
  232. params := after
  233. for len(params) > 0 {
  234. params = utils.TrimSpace(params)
  235. if len(params) == 0 {
  236. return ""
  237. }
  238. param := params
  239. if idx := bytes.IndexByte(params, ';'); idx != -1 {
  240. param = params[:idx]
  241. params = params[idx+1:]
  242. } else {
  243. params = nil
  244. }
  245. param = utils.TrimSpace(param)
  246. if len(param) == 0 {
  247. continue
  248. }
  249. before, after, ok := bytes.Cut(param, []byte{'='})
  250. if !ok {
  251. continue
  252. }
  253. name := utils.TrimSpace(before)
  254. if !bytes.EqualFold(name, []byte("charset")) {
  255. continue
  256. }
  257. value := utils.TrimSpace(after)
  258. if len(value) >= 2 && value[0] == '"' && value[len(value)-1] == '"' {
  259. value = value[1 : len(value)-1]
  260. }
  261. return c.app.toString(value)
  262. }
  263. return ""
  264. }
  265. // IsJSON reports whether the Content-Type header is JSON.
  266. func (c *DefaultCtx) IsJSON() bool {
  267. return utils.EqualFold(c.MediaType(), MIMEApplicationJSON)
  268. }
  269. // IsForm reports whether the Content-Type header is form-encoded.
  270. func (c *DefaultCtx) IsForm() bool {
  271. return utils.EqualFold(c.MediaType(), MIMEApplicationForm)
  272. }
  273. // IsMultipart reports whether the Content-Type header is multipart form data.
  274. func (c *DefaultCtx) IsMultipart() bool {
  275. return utils.EqualFold(c.MediaType(), MIMEMultipartForm)
  276. }
  277. // AcceptsJSON reports whether the Accept header allows JSON.
  278. func (c *DefaultCtx) AcceptsJSON() bool {
  279. return c.Accepts(MIMEApplicationJSON) != ""
  280. }
  281. // AcceptsHTML reports whether the Accept header allows HTML.
  282. func (c *DefaultCtx) AcceptsHTML() bool {
  283. return c.Accepts(MIMETextHTML) != ""
  284. }
  285. // AcceptsXML reports whether the Accept header allows XML.
  286. func (c *DefaultCtx) AcceptsXML() bool {
  287. return c.Accepts(MIMEApplicationXML, MIMETextXML) != ""
  288. }
  289. // AcceptsEventStream reports whether the Accept header allows text/event-stream.
  290. func (c *DefaultCtx) AcceptsEventStream() bool {
  291. return c.Accepts("text/event-stream") != ""
  292. }
  293. // Cookies are used for getting a cookie value by key.
  294. // Defaults to the empty string "" if the cookie doesn't exist.
  295. // If a default value is given, it will return that value if the cookie doesn't exist.
  296. // The returned value is only valid within the handler. Do not store any references.
  297. // Make copies or use the Immutable setting to use the value outside the Handler.
  298. func (r *DefaultReq) Cookies(key string, defaultValue ...string) string {
  299. return defaultString(r.c.app.toString(r.c.fasthttp.Request.Header.Cookie(key)), defaultValue)
  300. }
  301. // Request return the *fasthttp.Request object
  302. // This allows you to use all fasthttp request methods
  303. // https://godoc.org/github.com/valyala/fasthttp#Request
  304. func (r *DefaultReq) Request() *fasthttp.Request {
  305. return &r.c.fasthttp.Request
  306. }
  307. // FormFile returns the first file by key from a MultipartForm.
  308. // The multipart form is parsed using the application's BodyLimit to prevent
  309. // unbounded memory usage.
  310. func (r *DefaultReq) FormFile(key string) (*multipart.FileHeader, error) {
  311. if _, err := r.MultipartForm(); err != nil {
  312. return nil, err
  313. }
  314. return r.c.fasthttp.FormFile(key)
  315. }
  316. // FormValue returns the first value by key from a MultipartForm.
  317. // Search is performed in QueryArgs, PostArgs, MultipartForm and FormFile in this particular order.
  318. // Defaults to the empty string "" if the form value doesn't exist.
  319. // If a default value is given, it will return that value if the form value does not exist.
  320. // Returned value is only valid within the handler. Do not store any references.
  321. // Make copies or use the Immutable setting instead.
  322. // When the request is a multipart form, it is parsed using the application's
  323. // BodyLimit so the configured limit is consistently enforced.
  324. func (r *DefaultReq) FormValue(key string, defaultValue ...string) string {
  325. if r.c.IsMultipart() {
  326. // For multipart requests, parse the form using the application's BodyLimit.
  327. // fasthttp's FormValue would otherwise re-parse with its default 8 MiB limit,
  328. // effectively bypassing the configured BodyLimit.
  329. //
  330. // Preserve the original search order: QueryArgs → PostArgs → MultipartForm.
  331. if v := r.c.fasthttp.QueryArgs().Peek(key); len(v) > 0 {
  332. return r.c.app.toString(v)
  333. }
  334. if v := r.c.fasthttp.PostArgs().Peek(key); len(v) > 0 {
  335. return r.c.app.toString(v)
  336. }
  337. mf, err := r.MultipartForm()
  338. if err != nil {
  339. return defaultString("", defaultValue)
  340. }
  341. if vals := mf.Value[key]; len(vals) > 0 {
  342. return vals[0]
  343. }
  344. return defaultString("", defaultValue)
  345. }
  346. return defaultString(r.c.app.toString(r.c.fasthttp.FormValue(key)), defaultValue)
  347. }
  348. // Fresh returns true when the response is still “fresh” in the client's cache,
  349. // otherwise false is returned to indicate that the client cache is now stale
  350. // and the full response should be sent.
  351. // When a client sends the Cache-Control: no-cache request header to indicate an end-to-end
  352. // reload request, this module will return false to make handling these requests transparent.
  353. // https://github.com/jshttp/fresh/blob/master/index.js#L33
  354. func (r *DefaultReq) Fresh() bool {
  355. header := &r.c.fasthttp.Request.Header
  356. // fields
  357. modifiedSince := header.Peek(HeaderIfModifiedSince)
  358. noneMatch := header.Peek(HeaderIfNoneMatch)
  359. // unconditional request
  360. if len(modifiedSince) == 0 && len(noneMatch) == 0 {
  361. return false
  362. }
  363. // Always return stale when Cache-Control: no-cache
  364. // to support end-to-end reload requests
  365. // https://www.rfc-editor.org/rfc/rfc9111#section-5.2.1.4
  366. cacheControl := header.Peek(HeaderCacheControl)
  367. if len(cacheControl) > 0 && isNoCache(utils.UnsafeString(cacheControl)) {
  368. return false
  369. }
  370. // if-none-match
  371. if len(noneMatch) > 0 && (len(noneMatch) != 1 || noneMatch[0] != '*') {
  372. app := r.c.app
  373. response := &r.c.fasthttp.Response
  374. etag := app.toString(response.Header.Peek(HeaderETag))
  375. if etag == "" {
  376. return false
  377. }
  378. if app.isEtagStale(etag, noneMatch) {
  379. return false
  380. }
  381. if len(modifiedSince) > 0 {
  382. lastModified := response.Header.Peek(HeaderLastModified)
  383. if len(lastModified) > 0 {
  384. lastModifiedTime, err := fasthttp.ParseHTTPDate(lastModified)
  385. if err != nil {
  386. return false
  387. }
  388. modifiedSinceTime, err := fasthttp.ParseHTTPDate(modifiedSince)
  389. if err != nil {
  390. return false
  391. }
  392. return lastModifiedTime.Compare(modifiedSinceTime) != 1
  393. }
  394. }
  395. }
  396. return true
  397. }
  398. // Get returns the HTTP request header specified by field.
  399. // Field names are case-insensitive
  400. // Returned value is only valid within the handler. Do not store any references.
  401. // Make copies or use the Immutable setting instead.
  402. func (r *DefaultReq) Get(key string, defaultValue ...string) string {
  403. return GetReqHeader(r.c, key, defaultValue...)
  404. }
  405. // GetReqHeader returns the HTTP request header specified by filed.
  406. // This function is generic and can handle different headers type values.
  407. // If the generic type cannot be matched to a supported type, the function
  408. // returns the default value (if provided) or the zero value of type V.
  409. func GetReqHeader[V GenericType](c Ctx, key string, defaultValue ...V) V {
  410. v, err := genericParseType[V](c.App().toString(c.Request().Header.Peek(key)))
  411. if err != nil && len(defaultValue) > 0 {
  412. return defaultValue[0]
  413. }
  414. return v
  415. }
  416. // GetHeaders (a.k.a GetReqHeaders) returns the HTTP request headers.
  417. // Returned value is only valid within the handler. Do not store any references.
  418. // Make copies or use the Immutable setting instead.
  419. func (r *DefaultReq) GetHeaders() map[string][]string {
  420. app := r.c.app
  421. reqHeader := &r.c.fasthttp.Request.Header
  422. // Pre-allocate map with known header count to avoid reallocations
  423. headers := make(map[string][]string, reqHeader.Len())
  424. for k, v := range reqHeader.All() {
  425. key := app.toString(k)
  426. headers[key] = append(headers[key], app.toString(v))
  427. }
  428. return headers
  429. }
  430. // Host contains the host derived from the X-Forwarded-Host or Host HTTP header.
  431. // Returned value is only valid within the handler. Do not store any references.
  432. // In a network context, `Host` refers to the combination of a hostname and potentially a port number used for connecting,
  433. // while `Hostname` refers specifically to the name assigned to a device on a network, excluding any port information.
  434. // Example: URL: https://example.com:8080 -> Host: example.com:8080
  435. // Make copies or use the Immutable setting instead.
  436. // Please use Config.TrustProxy to prevent header spoofing if your app is behind a proxy.
  437. func (r *DefaultReq) Host() string {
  438. if r.IsProxyTrusted() {
  439. if host := r.Get(HeaderXForwardedHost); host != "" {
  440. if before, _, found := strings.Cut(host, ","); found {
  441. return utils.TrimSpace(before)
  442. }
  443. return utils.TrimSpace(host)
  444. }
  445. }
  446. return r.c.app.toString(r.c.fasthttp.Request.URI().Host())
  447. }
  448. // Hostname contains the hostname derived from the X-Forwarded-Host or Host HTTP header using the c.Host() method.
  449. // Returned value is only valid within the handler. Do not store any references.
  450. // Example: URL: https://example.com:8080 -> Hostname: example.com
  451. // Make copies or use the Immutable setting instead.
  452. // Please use Config.TrustProxy to prevent header spoofing if your app is behind a proxy.
  453. func (r *DefaultReq) Hostname() string {
  454. addr, _ := parseAddr(r.Host())
  455. return addr
  456. }
  457. // Port returns the remote port of the request.
  458. func (r *DefaultReq) Port() string {
  459. addr := r.c.fasthttp.RemoteAddr()
  460. if addr == nil {
  461. return "0"
  462. }
  463. switch typedAddr := addr.(type) {
  464. case *net.TCPAddr:
  465. return strconv.Itoa(typedAddr.Port)
  466. case *net.UnixAddr:
  467. return ""
  468. }
  469. _, port, err := net.SplitHostPort(addr.String())
  470. if err != nil {
  471. return ""
  472. }
  473. return port
  474. }
  475. // IP returns the remote IP address of the request.
  476. // If ProxyHeader and IP Validation is configured, it will parse that header and return the first valid IP address.
  477. // Please use Config.TrustProxy to prevent header spoofing if your app is behind a proxy.
  478. func (r *DefaultReq) IP() string {
  479. app := r.c.app
  480. if r.IsProxyTrusted() && app.config.ProxyHeader != "" {
  481. return r.extractIPFromHeader(app.config.ProxyHeader)
  482. }
  483. if ip := r.c.fasthttp.RemoteIP(); ip != nil {
  484. return ip.String()
  485. }
  486. return ""
  487. }
  488. // extractIPsFromHeader will return a slice of IPs it found given a header name in the order they appear.
  489. // When IP validation is enabled, any invalid IPs will be omitted.
  490. func (r *DefaultReq) extractIPsFromHeader(header string) []string {
  491. // TODO: Reuse the c.extractIPFromHeader func somehow in here
  492. headerValue := r.Get(header)
  493. // We can't know how many IPs we will return, but we will try to guess with this constant division.
  494. // Counting ',' makes function slower for about 50ns in general case.
  495. const maxEstimatedCount = 8
  496. estimatedCount := min(len(headerValue)/maxEstimatedCount,
  497. // Avoid big allocation on big header
  498. maxEstimatedCount)
  499. ipsFound := make([]string, 0, estimatedCount)
  500. i := 0
  501. j := -1
  502. for {
  503. var v4, v6 bool
  504. // Manually splitting string without allocating slice, working with parts directly
  505. i, j = j+1, j+2
  506. if j > len(headerValue) {
  507. break
  508. }
  509. for j < len(headerValue) && headerValue[j] != ',' {
  510. switch headerValue[j] {
  511. case ':':
  512. v6 = true
  513. case '.':
  514. v4 = true
  515. default:
  516. // do nothing
  517. }
  518. j++
  519. }
  520. for i < j && (headerValue[i] == ' ' || headerValue[i] == ',') {
  521. i++
  522. }
  523. s := utils.TrimRight(headerValue[i:j], ' ')
  524. if r.c.app.config.EnableIPValidation {
  525. // Skip validation if IP is clearly not IPv4/IPv6; otherwise, validate without allocations
  526. if (!v6 && !v4) || (v6 && !utils.IsIPv6(s)) || (v4 && !utils.IsIPv4(s)) {
  527. continue
  528. }
  529. }
  530. ipsFound = append(ipsFound, s)
  531. }
  532. return ipsFound
  533. }
  534. // extractIPFromHeader will attempt to pull the real client IP from the given header when IP validation is enabled.
  535. // currently, it will return the first valid IP address in header.
  536. // when IP validation is disabled, it will simply return the value of the header without any inspection.
  537. // Implementation is almost the same as in extractIPsFromHeader, but without allocation of []string.
  538. func (r *DefaultReq) extractIPFromHeader(header string) string {
  539. app := r.c.app
  540. if app.config.EnableIPValidation {
  541. headerValue := r.Get(header)
  542. i := 0
  543. j := -1
  544. for {
  545. var v4, v6 bool
  546. // Manually splitting string without allocating slice, working with parts directly
  547. i, j = j+1, j+2
  548. if j > len(headerValue) {
  549. break
  550. }
  551. for j < len(headerValue) && headerValue[j] != ',' {
  552. switch headerValue[j] {
  553. case ':':
  554. v6 = true
  555. case '.':
  556. v4 = true
  557. default:
  558. // do nothing
  559. }
  560. j++
  561. }
  562. for i < j && headerValue[i] == ' ' {
  563. i++
  564. }
  565. s := utils.TrimRight(headerValue[i:j], ' ')
  566. if app.config.EnableIPValidation {
  567. if (!v6 && !v4) || (v6 && !utils.IsIPv6(s)) || (v4 && !utils.IsIPv4(s)) {
  568. continue
  569. }
  570. }
  571. return s
  572. }
  573. if ip := r.c.fasthttp.RemoteIP(); ip != nil {
  574. return ip.String()
  575. }
  576. return ""
  577. }
  578. // default behavior if IP validation is not enabled is just to return whatever value is
  579. // in the proxy header. Even if it is empty or invalid
  580. return r.Get(app.config.ProxyHeader)
  581. }
  582. // IPs returns a string slice of IP addresses specified in the X-Forwarded-For request header.
  583. // When IP validation is enabled, only valid IPs are returned.
  584. func (r *DefaultReq) IPs() []string {
  585. return r.extractIPsFromHeader(HeaderXForwardedFor)
  586. }
  587. // Is returns the matching content type,
  588. // if the incoming request's Content-Type HTTP header field matches the MIME type specified by the type parameter
  589. func (r *DefaultReq) Is(extension string) bool {
  590. extensionHeader := utils.GetMIME(extension)
  591. if extensionHeader == "" {
  592. return false
  593. }
  594. ct := r.c.app.toString(r.c.fasthttp.Request.Header.ContentType())
  595. if i := strings.IndexByte(ct, ';'); i != -1 {
  596. ct = ct[:i]
  597. }
  598. ct = utils.TrimSpace(ct)
  599. return utils.EqualFold(ct, extensionHeader)
  600. }
  601. // Locals makes it possible to pass any values under keys scoped to the request
  602. // and therefore available to all following routes that match the request.
  603. //
  604. // All the values are removed from ctx after returning from the top
  605. // RequestHandler. Additionally, Close method is called on each value
  606. // implementing io.Closer before removing the value from ctx.
  607. func (r *DefaultReq) Locals(key any, value ...any) any {
  608. if len(value) == 0 {
  609. return r.c.fasthttp.UserValue(key)
  610. }
  611. r.c.fasthttp.SetUserValue(key, value[0])
  612. return value[0]
  613. }
  614. // Locals function utilizing Go's generics feature.
  615. // This function allows for manipulating and retrieving local values within a
  616. // request context with a more specific data type.
  617. //
  618. // All the values are removed from ctx after returning from the top
  619. // RequestHandler. Additionally, Close method is called on each value
  620. // implementing io.Closer before removing the value from ctx.
  621. func Locals[V any](c Ctx, key any, value ...V) V {
  622. var v V
  623. var ok bool
  624. if len(value) == 0 {
  625. v, ok = c.Locals(key).(V)
  626. } else {
  627. v, ok = c.Locals(key, value[0]).(V)
  628. }
  629. if !ok {
  630. return v // return zero of type V
  631. }
  632. return v
  633. }
  634. // Method returns the HTTP request method for the context, optionally overridden by the provided argument.
  635. // If no override is given or if the provided override is not a valid HTTP method, it returns the current method from the context.
  636. // Otherwise, it updates the context's method and returns the overridden method as a string.
  637. func (r *DefaultReq) Method(override ...string) string {
  638. app := r.c.app
  639. if len(override) == 0 {
  640. // Nothing to override, just return current method from context
  641. return app.method(r.c.methodInt)
  642. }
  643. method := utilsstrings.ToUpper(override[0])
  644. methodInt := app.methodInt(method)
  645. if methodInt == -1 {
  646. // Provided override does not valid HTTP method, no override, return current method
  647. return app.method(r.c.methodInt)
  648. }
  649. r.c.methodInt = methodInt
  650. return method
  651. }
  652. // MultipartForm parse form entries from binary.
  653. // This returns a map[string][]string, so given a key, the value will be a string slice.
  654. func (r *DefaultReq) MultipartForm() (*multipart.Form, error) {
  655. return r.c.fasthttp.MultipartFormWithLimit(r.c.app.config.BodyLimit)
  656. }
  657. // OriginalURL contains the original request URL.
  658. // Returned value is only valid within the handler. Do not store any references.
  659. // Make copies or use the Immutable setting to use the value outside the Handler.
  660. func (r *DefaultReq) OriginalURL() string {
  661. return r.c.app.toString(r.c.fasthttp.Request.Header.RequestURI())
  662. }
  663. // Params is used to get the route parameters.
  664. // Defaults to empty string "" if the param doesn't exist.
  665. // If a default value is given, it will return that value if the param doesn't exist.
  666. // Returned value is only valid within the handler. Do not store any references.
  667. // Make copies or use the Immutable setting to use the value outside the Handler.
  668. func (r *DefaultReq) Params(key string, defaultValue ...string) string {
  669. if key == "*" || key == "+" {
  670. key += "1"
  671. }
  672. app := r.c.app
  673. route := r.c.Route()
  674. values := &r.c.values
  675. for i := range route.Params {
  676. if len(key) != len(route.Params[i]) {
  677. continue
  678. }
  679. if route.Params[i] == key || (!app.config.CaseSensitive && utils.EqualFold(route.Params[i], key)) {
  680. // if there is no value for the key
  681. if len(values) <= i || values[i] == "" {
  682. break
  683. }
  684. val := values[i]
  685. return r.c.app.GetString(val)
  686. }
  687. }
  688. return defaultString("", defaultValue)
  689. }
  690. // Params is used to get the route parameters.
  691. // This function is generic and can handle different route parameters type values.
  692. // If the generic type cannot be matched to a supported type, the function
  693. // returns the default value (if provided) or the zero value of type V.
  694. //
  695. // Example:
  696. //
  697. // http://example.com/user/:user -> http://example.com/user/john
  698. // Params[string](c, "user") -> returns john
  699. //
  700. // http://example.com/id/:id -> http://example.com/user/114
  701. // Params[int](c, "id") -> returns 114 as integer.
  702. //
  703. // http://example.com/id/:number -> http://example.com/id/john
  704. // Params[int](c, "number", 0) -> returns 0 because can't parse 'john' as integer.
  705. func Params[V GenericType](c Ctx, key string, defaultValue ...V) V {
  706. v, err := genericParseType[V](c.Params(key))
  707. if err != nil && len(defaultValue) > 0 {
  708. return defaultValue[0]
  709. }
  710. return v
  711. }
  712. // Scheme contains the request protocol string: http or https for TLS requests.
  713. // Please use Config.TrustProxy to prevent header spoofing if your app is behind a proxy.
  714. func (r *DefaultReq) Scheme() string {
  715. ctx := r.c.fasthttp
  716. if ctx.IsTLS() {
  717. return schemeHTTPS
  718. }
  719. if !r.IsProxyTrusted() {
  720. return schemeHTTP
  721. }
  722. app := r.c.app
  723. scheme := schemeHTTP
  724. const lenXHeaderName = 12
  725. for key, val := range ctx.Request.Header.All() {
  726. if len(key) < lenXHeaderName {
  727. continue // Neither "X-Forwarded-" nor "X-Url-Scheme"
  728. }
  729. switch {
  730. case utils.EqualFold(key[:len(xForwardedPrefix)], xForwardedPrefix):
  731. if utils.EqualFold(key, xForwardedProtoBytes) ||
  732. utils.EqualFold(key, xForwardedProtocolBytes) {
  733. v := app.toString(val)
  734. if before, _, found := strings.Cut(v, ","); found {
  735. scheme = utils.TrimSpace(before)
  736. } else {
  737. scheme = utils.TrimSpace(v)
  738. }
  739. } else if utils.EqualFold(key, xForwardedSslBytes) && utils.EqualFold(val, onBytes) {
  740. scheme = schemeHTTPS
  741. }
  742. case utils.EqualFold(key, xURLSchemeBytes):
  743. scheme = utils.TrimSpace(app.toString(val))
  744. default:
  745. continue
  746. }
  747. }
  748. return utilsstrings.ToLower(utils.TrimSpace(scheme))
  749. }
  750. // Protocol returns the HTTP protocol of request: HTTP/1.1 and HTTP/2.
  751. func (r *DefaultReq) Protocol() string {
  752. return r.c.app.toString(r.c.fasthttp.Request.Header.Protocol())
  753. }
  754. // Query returns the query string parameter in the url.
  755. // Defaults to empty string "" if the query doesn't exist.
  756. // If a default value is given, it will return that value if the query doesn't exist.
  757. // Returned value is only valid within the handler. Do not store any references.
  758. // Make copies or use the Immutable setting to use the value outside the Handler.
  759. func (r *DefaultReq) Query(key string, defaultValue ...string) string {
  760. return Query(r.c, key, defaultValue...)
  761. }
  762. // Queries returns a map of query parameters and their values.
  763. //
  764. // GET /?name=alex&wanna_cake=2&id=
  765. // Queries()["name"] == "alex"
  766. // Queries()["wanna_cake"] == "2"
  767. // Queries()["id"] == ""
  768. //
  769. // GET /?field1=value1&field1=value2&field2=value3
  770. // Queries()["field1"] == "value2"
  771. // Queries()["field2"] == "value3"
  772. //
  773. // GET /?list_a=1&list_a=2&list_a=3&list_b[]=1&list_b[]=2&list_b[]=3&list_c=1,2,3
  774. // Queries()["list_a"] == "3"
  775. // Queries()["list_b[]"] == "3"
  776. // Queries()["list_c"] == "1,2,3"
  777. //
  778. // GET /api/search?filters.author.name=John&filters.category.name=Technology&filters[customer][name]=Alice&filters[status]=pending
  779. // Queries()["filters.author.name"] == "John"
  780. // Queries()["filters.category.name"] == "Technology"
  781. // Queries()["filters[customer][name]"] == "Alice"
  782. // Queries()["filters[status]"] == "pending"
  783. func (r *DefaultReq) Queries() map[string]string {
  784. app := r.c.app
  785. queryArgs := r.c.fasthttp.QueryArgs()
  786. m := make(map[string]string, queryArgs.Len())
  787. for key, value := range queryArgs.All() {
  788. m[app.toString(key)] = app.toString(value)
  789. }
  790. return m
  791. }
  792. // Query Retrieves the value of a query parameter from the request's URI.
  793. // The function is generic and can handle query parameter values of different types.
  794. // It takes the following parameters:
  795. // - c: The context object representing the current request.
  796. // - key: The name of the query parameter.
  797. // - defaultValue: (Optional) The default value to return if the query parameter is not found or cannot be parsed.
  798. // The function performs the following steps:
  799. // 1. Type-asserts the context object to *DefaultCtx.
  800. // 2. Retrieves the raw query parameter value from the request's URI.
  801. // 3. Parses the raw value into the appropriate type based on the generic type parameter V.
  802. // If parsing fails, the function checks if a default value is provided. If so, it returns the default value.
  803. // 4. Returns the parsed value.
  804. //
  805. // If the generic type cannot be matched to a supported type, the function returns the default value (if provided) or the zero value of type V.
  806. //
  807. // Example usage:
  808. //
  809. // GET /?search=john&age=8
  810. // name := Query[string](c, "search") // Returns "john"
  811. // age := Query[int](c, "age") // Returns 8
  812. // unknown := Query[string](c, "unknown", "default") // Returns "default" since the query parameter "unknown" is not found
  813. func Query[V GenericType](c Ctx, key string, defaultValue ...V) V {
  814. q := c.App().toString(c.RequestCtx().QueryArgs().Peek(key))
  815. v, err := genericParseType[V](q)
  816. if err != nil && len(defaultValue) > 0 {
  817. return defaultValue[0]
  818. }
  819. return v
  820. }
  821. // Range returns a struct containing the type and a slice of ranges.
  822. func (r *DefaultReq) Range(size int64) (Range, error) {
  823. var (
  824. rangeData Range
  825. ranges string
  826. )
  827. rangeStr := utils.TrimSpace(r.Get(HeaderRange))
  828. maxRanges := r.c.app.config.MaxRanges
  829. const maxRangePrealloc = 8
  830. prealloc := min(maxRanges, maxRangePrealloc)
  831. if prealloc > 0 {
  832. rangeData.Ranges = make([]RangeSet, 0, prealloc)
  833. }
  834. parseBound := func(value string) (int64, error) {
  835. parsed, err := utils.ParseUint(value)
  836. if err != nil {
  837. return 0, fmt.Errorf("parse range bound %q: %w", value, err)
  838. }
  839. if parsed > (math.MaxUint64 >> 1) {
  840. return 0, ErrRangeMalformed
  841. }
  842. return int64(parsed), nil
  843. }
  844. before, after, found := strings.Cut(rangeStr, "=")
  845. if !found || strings.IndexByte(after, '=') >= 0 {
  846. return rangeData, ErrRangeMalformed
  847. }
  848. rangeData.Type = utilsstrings.ToLower(utils.TrimSpace(before))
  849. if rangeData.Type != "bytes" {
  850. return rangeData, ErrRangeMalformed
  851. }
  852. ranges = utils.TrimSpace(after)
  853. var (
  854. singleRange string
  855. moreRanges = ranges
  856. rangeCount int
  857. )
  858. for moreRanges != "" {
  859. rangeCount++
  860. if rangeCount > maxRanges {
  861. r.c.DefaultRes.Status(StatusRequestedRangeNotSatisfiable)
  862. r.c.DefaultRes.Set(HeaderContentRange, "bytes */"+utils.FormatInt(size)) //nolint:staticcheck // It is fine to ignore the static check
  863. return rangeData, ErrRangeTooLarge
  864. }
  865. singleRange = moreRanges
  866. if i := strings.IndexByte(moreRanges, ','); i >= 0 {
  867. singleRange = moreRanges[:i]
  868. moreRanges = utils.TrimSpace(moreRanges[i+1:])
  869. } else {
  870. moreRanges = ""
  871. }
  872. singleRange = utils.TrimSpace(singleRange)
  873. var (
  874. startStr, endStr string
  875. i int
  876. )
  877. if i = strings.IndexByte(singleRange, '-'); i == -1 {
  878. return rangeData, ErrRangeMalformed
  879. }
  880. startStr = utils.TrimSpace(singleRange[:i])
  881. endStr = utils.TrimSpace(singleRange[i+1:])
  882. start, startErr := parseBound(startStr)
  883. end, endErr := parseBound(endStr)
  884. if errors.Is(startErr, ErrRangeMalformed) || errors.Is(endErr, ErrRangeMalformed) {
  885. return rangeData, ErrRangeMalformed
  886. }
  887. if startErr != nil { // -nnn
  888. start = max(size-end, 0)
  889. end = size - 1
  890. } else if endErr != nil { // nnn-
  891. end = size - 1
  892. }
  893. if end > size-1 { // limit last-byte-pos to current length
  894. end = size - 1
  895. }
  896. if start > end || start < 0 {
  897. continue
  898. }
  899. rangeData.Ranges = append(rangeData.Ranges, RangeSet{
  900. Start: start,
  901. End: end,
  902. })
  903. }
  904. if len(rangeData.Ranges) < 1 {
  905. r.c.DefaultRes.Status(StatusRequestedRangeNotSatisfiable)
  906. r.c.DefaultRes.Set(HeaderContentRange, "bytes */"+utils.FormatInt(size)) //nolint:staticcheck // It is fine to ignore the static check
  907. return rangeData, ErrRequestedRangeNotSatisfiable
  908. }
  909. return rangeData, nil
  910. }
  911. // Route returns the matched Route struct.
  912. func (r *DefaultReq) Route() *Route {
  913. return r.c.Route()
  914. }
  915. // Subdomains returns a slice of subdomains from the host, excluding the last `offset` components.
  916. // If the offset is negative or exceeds the number of subdomains, an empty slice is returned.
  917. // If the offset is zero every label (no trimming) is returned.
  918. func (r *DefaultReq) Subdomains(offset ...int) []string {
  919. o := 2
  920. if len(offset) > 0 {
  921. o = offset[0]
  922. }
  923. // Negative offset, return nothing.
  924. if o < 0 {
  925. return []string{}
  926. }
  927. // Normalize host according to RFC 3986
  928. host := r.Hostname()
  929. // Trim the trailing dot of a fully-qualified domain
  930. if strings.HasSuffix(host, ".") {
  931. host = utils.TrimRight(host, '.')
  932. }
  933. host = utilsstrings.ToLower(host)
  934. // Decode punycode labels only when necessary
  935. if strings.Contains(host, "xn--") {
  936. if u, err := idna.Lookup.ToUnicode(host); err == nil {
  937. host = utilsstrings.ToLower(u)
  938. }
  939. }
  940. // Return nothing for IP addresses
  941. ip := host
  942. if strings.HasPrefix(ip, "[") && strings.HasSuffix(ip, "]") {
  943. ip = ip[1 : len(ip)-1]
  944. }
  945. if utils.IsIPv4(ip) || utils.IsIPv6(ip) {
  946. return []string{}
  947. }
  948. // Use stack-allocated array for typical domain names (up to 8 labels)
  949. // This avoids heap allocation for most common cases
  950. var partsBuf [8]string
  951. parts := partsBuf[:0]
  952. for part := range strings.SplitSeq(host, ".") {
  953. parts = append(parts, part)
  954. }
  955. // offset == 0, caller wants everything.
  956. if o == 0 {
  957. // Need to return a copy since partsBuf is on the stack
  958. result := make([]string, len(parts))
  959. copy(result, parts)
  960. return result
  961. }
  962. // If we trim away the whole slice (or more), nothing remains.
  963. if o >= len(parts) {
  964. return []string{}
  965. }
  966. // Return a heap-allocated copy of the relevant portion
  967. result := make([]string, len(parts)-o)
  968. copy(result, parts[:len(parts)-o])
  969. return result
  970. }
  971. // Stale returns the inverse of Fresh, indicating if the client's cached response is considered stale.
  972. func (r *DefaultReq) Stale() bool {
  973. return !r.Fresh()
  974. }
  975. // IsProxyTrusted checks trustworthiness of remote ip.
  976. // If Config.TrustProxy false, it returns false.
  977. // IsProxyTrusted can check remote ip by proxy ranges and ip map.
  978. func (r *DefaultReq) IsProxyTrusted() bool {
  979. config := r.c.app.config
  980. if !config.TrustProxy {
  981. return false
  982. }
  983. remoteAddr := r.c.fasthttp.RemoteAddr()
  984. switch remoteAddr.(type) {
  985. case *net.UnixAddr:
  986. return config.TrustProxyConfig.UnixSocket
  987. case *net.TCPAddr, *net.UDPAddr:
  988. // Keep existing RemoteIP/IP-map/CIDR checks for TCP/UDP paths as-is.
  989. default:
  990. // Unknown address type: do not trust by default.
  991. return false
  992. }
  993. ip := r.c.fasthttp.RemoteIP()
  994. if ip == nil {
  995. return false
  996. }
  997. if (config.TrustProxyConfig.Loopback && ip.IsLoopback()) ||
  998. (config.TrustProxyConfig.Private && ip.IsPrivate()) ||
  999. (config.TrustProxyConfig.LinkLocal && ip.IsLinkLocalUnicast()) {
  1000. return true
  1001. }
  1002. if _, trusted := config.TrustProxyConfig.ips[ip.String()]; trusted {
  1003. return true
  1004. }
  1005. for _, ipNet := range config.TrustProxyConfig.ranges {
  1006. if ipNet.Contains(ip) {
  1007. return true
  1008. }
  1009. }
  1010. return false
  1011. }
  1012. // IsFromLocal will return true if request came from local.
  1013. func (r *DefaultReq) IsFromLocal() bool {
  1014. // Unix sockets are inherently local - only processes on the same host can connect.
  1015. remoteAddr := r.c.fasthttp.RemoteAddr()
  1016. if _, ok := remoteAddr.(*net.UnixAddr); ok {
  1017. return true
  1018. }
  1019. if ip := r.c.fasthttp.RemoteIP(); ip != nil {
  1020. return ip.IsLoopback()
  1021. }
  1022. return false
  1023. }
  1024. // Release is a method to reset Req fields when to use ReleaseCtx()
  1025. func (r *DefaultReq) release() {
  1026. r.c = nil
  1027. }
  1028. func (r *DefaultReq) getBody() []byte {
  1029. return r.c.app.GetBytes(r.c.fasthttp.Request.Body())
  1030. }