req.go 36 KB

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