mirror of https://github.com/gofiber/fiber.git
Merge branch 'main' into update-redirect
commit
9d79488dec
10
bind.go
10
bind.go
|
@ -95,7 +95,7 @@ func (b *Bind) RespHeader(out any) error {
|
||||||
// Cookie binds the requesr cookie strings into the struct, map[string]string and map[string][]string.
|
// Cookie binds the requesr cookie strings into the struct, map[string]string and map[string][]string.
|
||||||
// NOTE: If your cookie is like key=val1,val2; they'll be binded as an slice if your map is map[string][]string. Else, it'll use last element of cookie.
|
// NOTE: If your cookie is like key=val1,val2; they'll be binded as an slice if your map is map[string][]string. Else, it'll use last element of cookie.
|
||||||
func (b *Bind) Cookie(out any) error {
|
func (b *Bind) Cookie(out any) error {
|
||||||
if err := b.returnErr(binder.CookieBinder.Bind(b.ctx.Context(), out)); err != nil {
|
if err := b.returnErr(binder.CookieBinder.Bind(b.ctx.RequestCtx(), out)); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,7 +104,7 @@ func (b *Bind) Cookie(out any) error {
|
||||||
|
|
||||||
// Query binds the query string into the struct, map[string]string and map[string][]string.
|
// Query binds the query string into the struct, map[string]string and map[string][]string.
|
||||||
func (b *Bind) Query(out any) error {
|
func (b *Bind) Query(out any) error {
|
||||||
if err := b.returnErr(binder.QueryBinder.Bind(b.ctx.Context(), out)); err != nil {
|
if err := b.returnErr(binder.QueryBinder.Bind(b.ctx.RequestCtx(), out)); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,7 +131,7 @@ func (b *Bind) XML(out any) error {
|
||||||
|
|
||||||
// Form binds the form into the struct, map[string]string and map[string][]string.
|
// Form binds the form into the struct, map[string]string and map[string][]string.
|
||||||
func (b *Bind) Form(out any) error {
|
func (b *Bind) Form(out any) error {
|
||||||
if err := b.returnErr(binder.FormBinder.Bind(b.ctx.Context(), out)); err != nil {
|
if err := b.returnErr(binder.FormBinder.Bind(b.ctx.RequestCtx(), out)); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -149,7 +149,7 @@ func (b *Bind) URI(out any) error {
|
||||||
|
|
||||||
// MultipartForm binds the multipart form into the struct, map[string]string and map[string][]string.
|
// MultipartForm binds the multipart form into the struct, map[string]string and map[string][]string.
|
||||||
func (b *Bind) MultipartForm(out any) error {
|
func (b *Bind) MultipartForm(out any) error {
|
||||||
if err := b.returnErr(binder.FormBinder.BindMultipart(b.ctx.Context(), out)); err != nil {
|
if err := b.returnErr(binder.FormBinder.BindMultipart(b.ctx.RequestCtx(), out)); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -163,7 +163,7 @@ func (b *Bind) MultipartForm(out any) error {
|
||||||
// If there're no custom binder for mime type of body, it will return a ErrUnprocessableEntity error.
|
// If there're no custom binder for mime type of body, it will return a ErrUnprocessableEntity error.
|
||||||
func (b *Bind) Body(out any) error {
|
func (b *Bind) Body(out any) error {
|
||||||
// Get content-type
|
// Get content-type
|
||||||
ctype := utils.ToLower(utils.UnsafeString(b.ctx.Context().Request.Header.ContentType()))
|
ctype := utils.ToLower(utils.UnsafeString(b.ctx.RequestCtx().Request.Header.ContentType()))
|
||||||
ctype = binder.FilterFlags(utils.ParseVendorSpecificContentType(ctype))
|
ctype = binder.FilterFlags(utils.ParseVendorSpecificContentType(ctype))
|
||||||
|
|
||||||
// Check custom binders
|
// Check custom binders
|
||||||
|
|
|
@ -1572,7 +1572,7 @@ func Test_Client_SetProxyURL(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Status(resp.StatusCode())
|
c.Status(resp.StatusCode())
|
||||||
c.Context().SetBody(resp.Body())
|
c.RequestCtx().SetBody(resp.Body())
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
22
ctx.go
22
ctx.go
|
@ -382,26 +382,26 @@ func (c *DefaultCtx) ClearCookie(key ...string) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Context returns *fasthttp.RequestCtx that carries a deadline
|
// RequestCtx returns *fasthttp.RequestCtx that carries a deadline
|
||||||
// a cancellation signal, and other values across API boundaries.
|
// a cancellation signal, and other values across API boundaries.
|
||||||
func (c *DefaultCtx) Context() *fasthttp.RequestCtx {
|
func (c *DefaultCtx) RequestCtx() *fasthttp.RequestCtx {
|
||||||
return c.fasthttp
|
return c.fasthttp
|
||||||
}
|
}
|
||||||
|
|
||||||
// UserContext returns a context implementation that was set by
|
// Context returns a context implementation that was set by
|
||||||
// user earlier or returns a non-nil, empty context,if it was not set earlier.
|
// user earlier or returns a non-nil, empty context,if it was not set earlier.
|
||||||
func (c *DefaultCtx) UserContext() context.Context {
|
func (c *DefaultCtx) Context() context.Context {
|
||||||
ctx, ok := c.fasthttp.UserValue(userContextKey).(context.Context)
|
ctx, ok := c.fasthttp.UserValue(userContextKey).(context.Context)
|
||||||
if !ok {
|
if !ok {
|
||||||
ctx = context.Background()
|
ctx = context.Background()
|
||||||
c.SetUserContext(ctx)
|
c.SetContext(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
return ctx
|
return ctx
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetUserContext sets a context implementation by user.
|
// SetContext sets a context implementation by user.
|
||||||
func (c *DefaultCtx) SetUserContext(ctx context.Context) {
|
func (c *DefaultCtx) SetContext(ctx context.Context) {
|
||||||
c.fasthttp.SetUserValue(userContextKey, ctx)
|
c.fasthttp.SetUserValue(userContextKey, ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1189,8 +1189,8 @@ func (c *DefaultCtx) Query(key string, defaultValue ...string) string {
|
||||||
// Queries()["filters[customer][name]"] == "Alice"
|
// Queries()["filters[customer][name]"] == "Alice"
|
||||||
// Queries()["filters[status]"] == "pending"
|
// Queries()["filters[status]"] == "pending"
|
||||||
func (c *DefaultCtx) Queries() map[string]string {
|
func (c *DefaultCtx) Queries() map[string]string {
|
||||||
m := make(map[string]string, c.Context().QueryArgs().Len())
|
m := make(map[string]string, c.RequestCtx().QueryArgs().Len())
|
||||||
c.Context().QueryArgs().VisitAll(func(key, value []byte) {
|
c.RequestCtx().QueryArgs().VisitAll(func(key, value []byte) {
|
||||||
m[c.app.getString(key)] = c.app.getString(value)
|
m[c.app.getString(key)] = c.app.getString(value)
|
||||||
})
|
})
|
||||||
return m
|
return m
|
||||||
|
@ -1219,7 +1219,7 @@ func (c *DefaultCtx) Queries() map[string]string {
|
||||||
// unknown := Query[string](c, "unknown", "default") // Returns "default" since the query parameter "unknown" is not found
|
// unknown := Query[string](c, "unknown", "default") // Returns "default" since the query parameter "unknown" is not found
|
||||||
func Query[V GenericType](c Ctx, key string, defaultValue ...V) V {
|
func Query[V GenericType](c Ctx, key string, defaultValue ...V) V {
|
||||||
var v V
|
var v V
|
||||||
q := c.App().getString(c.Context().QueryArgs().Peek(key))
|
q := c.App().getString(c.RequestCtx().QueryArgs().Peek(key))
|
||||||
|
|
||||||
return genericParseType[V](q, v, defaultValue...)
|
return genericParseType[V](q, v, defaultValue...)
|
||||||
}
|
}
|
||||||
|
@ -1630,7 +1630,7 @@ func (c *DefaultCtx) SendFile(file string, config ...SendFile) error {
|
||||||
// Apply cache control header
|
// Apply cache control header
|
||||||
if status != StatusNotFound && status != StatusForbidden {
|
if status != StatusNotFound && status != StatusForbidden {
|
||||||
if len(cacheControlValue) > 0 {
|
if len(cacheControlValue) > 0 {
|
||||||
c.Context().Response.Header.Set(HeaderCacheControl, cacheControlValue)
|
c.RequestCtx().Response.Header.Set(HeaderCacheControl, cacheControlValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -45,14 +45,14 @@ type Ctx interface {
|
||||||
// ClearCookie expires a specific cookie by key on the client side.
|
// ClearCookie expires a specific cookie by key on the client side.
|
||||||
// If no key is provided it expires all cookies that came with the request.
|
// If no key is provided it expires all cookies that came with the request.
|
||||||
ClearCookie(key ...string)
|
ClearCookie(key ...string)
|
||||||
// Context returns *fasthttp.RequestCtx that carries a deadline
|
// RequestCtx returns *fasthttp.RequestCtx that carries a deadline
|
||||||
// a cancellation signal, and other values across API boundaries.
|
// a cancellation signal, and other values across API boundaries.
|
||||||
Context() *fasthttp.RequestCtx
|
RequestCtx() *fasthttp.RequestCtx
|
||||||
// UserContext returns a context implementation that was set by
|
// Context returns a context implementation that was set by
|
||||||
// user earlier or returns a non-nil, empty context,if it was not set earlier.
|
// user earlier or returns a non-nil, empty context,if it was not set earlier.
|
||||||
UserContext() context.Context
|
Context() context.Context
|
||||||
// SetUserContext sets a context implementation by user.
|
// SetContext sets a context implementation by user.
|
||||||
SetUserContext(ctx context.Context)
|
SetContext(ctx context.Context)
|
||||||
// Cookie sets a cookie by passing a cookie struct.
|
// Cookie sets a cookie by passing a cookie struct.
|
||||||
Cookie(cookie *Cookie)
|
Cookie(cookie *Cookie)
|
||||||
// Cookies are used for getting a cookie value by key.
|
// Cookies are used for getting a cookie value by key.
|
||||||
|
|
40
ctx_test.go
40
ctx_test.go
|
@ -843,24 +843,24 @@ func Benchmark_Ctx_Body_With_Compression_Immutable(b *testing.B) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// go test -run Test_Ctx_RequestCtx
|
||||||
|
func Test_Ctx_RequestCtx(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
app := New()
|
||||||
|
c := app.AcquireCtx(&fasthttp.RequestCtx{})
|
||||||
|
|
||||||
|
require.Equal(t, "*fasthttp.RequestCtx", fmt.Sprintf("%T", c.RequestCtx()))
|
||||||
|
}
|
||||||
|
|
||||||
// go test -run Test_Ctx_Context
|
// go test -run Test_Ctx_Context
|
||||||
func Test_Ctx_Context(t *testing.T) {
|
func Test_Ctx_Context(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
app := New()
|
app := New()
|
||||||
c := app.AcquireCtx(&fasthttp.RequestCtx{})
|
c := app.AcquireCtx(&fasthttp.RequestCtx{})
|
||||||
|
|
||||||
require.Equal(t, "*fasthttp.RequestCtx", fmt.Sprintf("%T", c.Context()))
|
|
||||||
}
|
|
||||||
|
|
||||||
// go test -run Test_Ctx_UserContext
|
|
||||||
func Test_Ctx_UserContext(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
app := New()
|
|
||||||
c := app.AcquireCtx(&fasthttp.RequestCtx{})
|
|
||||||
|
|
||||||
t.Run("Nil_Context", func(t *testing.T) {
|
t.Run("Nil_Context", func(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
ctx := c.UserContext()
|
ctx := c.Context()
|
||||||
require.Equal(t, ctx, context.Background())
|
require.Equal(t, ctx, context.Background())
|
||||||
})
|
})
|
||||||
t.Run("ValueContext", func(t *testing.T) {
|
t.Run("ValueContext", func(t *testing.T) {
|
||||||
|
@ -872,8 +872,8 @@ func Test_Ctx_UserContext(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// go test -run Test_Ctx_SetUserContext
|
// go test -run Test_Ctx_SetContext
|
||||||
func Test_Ctx_SetUserContext(t *testing.T) {
|
func Test_Ctx_SetContext(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
app := New()
|
app := New()
|
||||||
c := app.AcquireCtx(&fasthttp.RequestCtx{})
|
c := app.AcquireCtx(&fasthttp.RequestCtx{})
|
||||||
|
@ -881,19 +881,19 @@ func Test_Ctx_SetUserContext(t *testing.T) {
|
||||||
testKey := struct{}{}
|
testKey := struct{}{}
|
||||||
testValue := "Test Value"
|
testValue := "Test Value"
|
||||||
ctx := context.WithValue(context.Background(), testKey, testValue) //nolint: staticcheck // not needed for tests
|
ctx := context.WithValue(context.Background(), testKey, testValue) //nolint: staticcheck // not needed for tests
|
||||||
c.SetUserContext(ctx)
|
c.SetContext(ctx)
|
||||||
require.Equal(t, testValue, c.UserContext().Value(testKey))
|
require.Equal(t, testValue, c.Context().Value(testKey))
|
||||||
}
|
}
|
||||||
|
|
||||||
// go test -run Test_Ctx_UserContext_Multiple_Requests
|
// go test -run Test_Ctx_Context_Multiple_Requests
|
||||||
func Test_Ctx_UserContext_Multiple_Requests(t *testing.T) {
|
func Test_Ctx_Context_Multiple_Requests(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
testKey := struct{}{}
|
testKey := struct{}{}
|
||||||
testValue := "foobar-value"
|
testValue := "foobar-value"
|
||||||
|
|
||||||
app := New()
|
app := New()
|
||||||
app.Get("/", func(c Ctx) error {
|
app.Get("/", func(c Ctx) error {
|
||||||
ctx := c.UserContext()
|
ctx := c.Context()
|
||||||
|
|
||||||
if ctx.Value(testKey) != nil {
|
if ctx.Value(testKey) != nil {
|
||||||
return c.SendStatus(StatusInternalServerError)
|
return c.SendStatus(StatusInternalServerError)
|
||||||
|
@ -901,7 +901,7 @@ func Test_Ctx_UserContext_Multiple_Requests(t *testing.T) {
|
||||||
|
|
||||||
input := utils.CopyString(Query(c, "input", "NO_VALUE"))
|
input := utils.CopyString(Query(c, "input", "NO_VALUE"))
|
||||||
ctx = context.WithValue(ctx, testKey, fmt.Sprintf("%s_%s", testValue, input)) //nolint: staticcheck // not needed for tests
|
ctx = context.WithValue(ctx, testKey, fmt.Sprintf("%s_%s", testValue, input)) //nolint: staticcheck // not needed for tests
|
||||||
c.SetUserContext(ctx)
|
c.SetContext(ctx)
|
||||||
|
|
||||||
return c.Status(StatusOK).SendString(fmt.Sprintf("resp_%s_returned", input))
|
return c.Status(StatusOK).SendString(fmt.Sprintf("resp_%s_returned", input))
|
||||||
})
|
})
|
||||||
|
@ -913,7 +913,7 @@ func Test_Ctx_UserContext_Multiple_Requests(t *testing.T) {
|
||||||
resp, err := app.Test(httptest.NewRequest(MethodGet, fmt.Sprintf("/?input=%d", i), nil))
|
resp, err := app.Test(httptest.NewRequest(MethodGet, fmt.Sprintf("/?input=%d", i), nil))
|
||||||
|
|
||||||
require.NoError(t, err, "Unexpected error from response")
|
require.NoError(t, err, "Unexpected error from response")
|
||||||
require.Equal(t, StatusOK, resp.StatusCode, "context.Context returned from c.UserContext() is reused")
|
require.Equal(t, StatusOK, resp.StatusCode, "context.Context returned from c.Context() is reused")
|
||||||
|
|
||||||
b, err := io.ReadAll(resp.Body)
|
b, err := io.ReadAll(resp.Body)
|
||||||
require.NoError(t, err, "Unexpected error from reading response body")
|
require.NoError(t, err, "Unexpected error from reading response body")
|
||||||
|
@ -3220,7 +3220,7 @@ func Test_Ctx_SendFile_MaxAge(t *testing.T) {
|
||||||
// check expectation
|
// check expectation
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, expectFileContent, c.Response().Body())
|
require.Equal(t, expectFileContent, c.Response().Body())
|
||||||
require.Equal(t, "public, max-age=100", string(c.Context().Response.Header.Peek(HeaderCacheControl)), "CacheControl Control")
|
require.Equal(t, "public, max-age=100", string(c.RequestCtx().Response.Header.Peek(HeaderCacheControl)), "CacheControl Control")
|
||||||
require.Equal(t, StatusOK, c.Response().StatusCode())
|
require.Equal(t, StatusOK, c.Response().StatusCode())
|
||||||
app.ReleaseCtx(c)
|
app.ReleaseCtx(c)
|
||||||
}
|
}
|
||||||
|
|
|
@ -354,15 +354,20 @@ app.Get("/hello", func(c fiber.Ctx) error {
|
||||||
|
|
||||||
## Context
|
## Context
|
||||||
|
|
||||||
Returns [\*fasthttp.RequestCtx](https://godoc.org/github.com/valyala/fasthttp#RequestCtx) that is compatible with the context.Context interface that requires a deadline, a cancellation signal, and other values across API boundaries.
|
Context returns a context implementation that was set by user earlier or returns a non-nil, empty context, if it was not set earlier.
|
||||||
|
|
||||||
```go title="Signature"
|
```go title="Signature"
|
||||||
func (c Ctx) Context() *fasthttp.RequestCtx
|
func (c Ctx) Context() context.Context
|
||||||
```
|
```
|
||||||
|
|
||||||
:::info
|
```go title="Example"
|
||||||
Please read the [Fasthttp Documentation](https://pkg.go.dev/github.com/valyala/fasthttp?tab=doc) for more information.
|
app.Get("/", func(c fiber.Ctx) error {
|
||||||
:::
|
ctx := c.Context()
|
||||||
|
// ctx is context implementation set by user
|
||||||
|
|
||||||
|
// ...
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
## Cookie
|
## Cookie
|
||||||
|
|
||||||
|
@ -1489,6 +1494,18 @@ app.Get("/", func(c fiber.Ctx) error {
|
||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## RequestCtx
|
||||||
|
|
||||||
|
Returns [\*fasthttp.RequestCtx](https://godoc.org/github.com/valyala/fasthttp#RequestCtx) that is compatible with the context.Context interface that requires a deadline, a cancellation signal, and other values across API boundaries.
|
||||||
|
|
||||||
|
```go title="Signature"
|
||||||
|
func (c Ctx) RequestCtx() *fasthttp.RequestCtx
|
||||||
|
```
|
||||||
|
|
||||||
|
:::info
|
||||||
|
Please read the [Fasthttp Documentation](https://pkg.go.dev/github.com/valyala/fasthttp?tab=doc) for more information.
|
||||||
|
:::
|
||||||
|
|
||||||
## Response
|
## Response
|
||||||
|
|
||||||
Response return the [\*fasthttp.Response](https://godoc.org/github.com/valyala/fasthttp#Response) pointer
|
Response return the [\*fasthttp.Response](https://godoc.org/github.com/valyala/fasthttp#Response) pointer
|
||||||
|
@ -1891,18 +1908,18 @@ app.Get("/", func(c fiber.Ctx) error {
|
||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
## SetUserContext
|
## SetContext
|
||||||
|
|
||||||
Sets the user specified implementation for context interface.
|
Sets the user specified implementation for context.Context interface.
|
||||||
|
|
||||||
```go title="Signature"
|
```go title="Signature"
|
||||||
func (c Ctx) SetUserContext(ctx context.Context)
|
func (c Ctx) SetContext(ctx context.Context)
|
||||||
```
|
```
|
||||||
|
|
||||||
```go title="Example"
|
```go title="Example"
|
||||||
app.Get("/", func(c fiber.Ctx) error {
|
app.Get("/", func(c fiber.Ctx) error {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
c.SetUserContext(ctx)
|
c.SetContext(ctx)
|
||||||
// Here ctx could be any context implementation
|
// Here ctx could be any context implementation
|
||||||
|
|
||||||
// ...
|
// ...
|
||||||
|
@ -2005,24 +2022,6 @@ app.Get("/", func(c fiber.Ctx) error {
|
||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
## UserContext
|
|
||||||
|
|
||||||
UserContext returns a context implementation that was set by user earlier
|
|
||||||
or returns a non-nil, empty context, if it was not set earlier.
|
|
||||||
|
|
||||||
```go title="Signature"
|
|
||||||
func (c Ctx) UserContext() context.Context
|
|
||||||
```
|
|
||||||
|
|
||||||
```go title="Example"
|
|
||||||
app.Get("/", func(c fiber.Ctx) error {
|
|
||||||
ctx := c.UserContext()
|
|
||||||
// ctx is context implementation set by user
|
|
||||||
|
|
||||||
// ...
|
|
||||||
})
|
|
||||||
```
|
|
||||||
|
|
||||||
## Vary
|
## Vary
|
||||||
|
|
||||||
Adds the given header field to the [Vary](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Vary) response header. This will append the header, if not already listed, otherwise leaves it listed in the current location.
|
Adds the given header field to the [Vary](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Vary) response header. This will append the header, if not already listed, otherwise leaves it listed in the current location.
|
||||||
|
|
|
@ -4,15 +4,15 @@ id: welcome
|
||||||
title: 👋 Welcome
|
title: 👋 Welcome
|
||||||
sidebar_position: 1
|
sidebar_position: 1
|
||||||
---
|
---
|
||||||
An online API documentation with examples so you can start building web apps with Fiber right away!
|
Welcome to the online API documentation for Fiber, complete with examples to help you start building web applications with Fiber right away!
|
||||||
|
|
||||||
**Fiber** is an [Express](https://github.com/expressjs/express) inspired **web framework** built on top of [Fasthttp](https://github.com/valyala/fasthttp), the **fastest** HTTP engine for [Go](https://go.dev/doc/). Designed to **ease** things up for **fast** development with **zero memory allocation** and **performance** in mind.
|
**Fiber** is an [Express](https://github.com/expressjs/express)-inspired **web framework** built on top of [Fasthttp](https://github.com/valyala/fasthttp), the **fastest** HTTP engine for [Go](https://go.dev/doc/). It is designed to facilitate rapid development with **zero memory allocations** and a strong focus on **performance**.
|
||||||
|
|
||||||
These docs are for **Fiber v3**, which was released on **March XX, 2024**.
|
These docs are for **Fiber v3**, which was released on **Month xx, 202x**.
|
||||||
|
|
||||||
### Installation
|
### Installation
|
||||||
|
|
||||||
First of all, [download](https://go.dev/dl/) and install Go. `1.22` or higher is required.
|
First, [download](https://go.dev/dl/) and install Go. Version `1.22` or higher is required.
|
||||||
|
|
||||||
Installation is done using the [`go get`](https://pkg.go.dev/cmd/go/#hdr-Add_dependencies_to_current_module_and_install_them) command:
|
Installation is done using the [`go get`](https://pkg.go.dev/cmd/go/#hdr-Add_dependencies_to_current_module_and_install_them) command:
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ go get github.com/gofiber/fiber/v3
|
||||||
|
|
||||||
### Zero Allocation
|
### Zero Allocation
|
||||||
|
|
||||||
Fiber is optimized for **high-performance**, meaning values returned from **fiber.Ctx** are **not** immutable by default and **will** be re-used across requests. As a rule of thumb, you **must** only use context values within the handler and **must not** keep any references. Once you return from the handler, any values obtained from the context will be re-used in future requests. Here is an example:
|
Fiber is optimized for **high performance**, meaning values returned from **fiber.Ctx** are **not** immutable by default and **will** be reused across requests. As a rule of thumb, you **must** only use context values within the handler and **must not** keep any references. Once you return from the handler, any values obtained from the context will be reused in future requests. Here is an example:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func handler(c fiber.Ctx) error {
|
func handler(c fiber.Ctx) error {
|
||||||
|
@ -44,13 +44,13 @@ func handler(c fiber.Ctx) error {
|
||||||
buffer := make([]byte, len(result))
|
buffer := make([]byte, len(result))
|
||||||
copy(buffer, result)
|
copy(buffer, result)
|
||||||
resultCopy := string(buffer)
|
resultCopy := string(buffer)
|
||||||
// Variable is now valid forever
|
// Variable is now valid indefinitely
|
||||||
|
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
We created a custom `CopyString` function that does the above and is available under [gofiber/utils](https://github.com/gofiber/utils).
|
We created a custom `CopyString` function that performs the above and is available under [gofiber/utils](https://github.com/gofiber/utils).
|
||||||
|
|
||||||
```go
|
```go
|
||||||
app.Get("/:foo", func(c fiber.Ctx) error {
|
app.Get("/:foo", func(c fiber.Ctx) error {
|
||||||
|
@ -61,7 +61,7 @@ app.Get("/:foo", func(c fiber.Ctx) error {
|
||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
Alternatively, you can also use the `Immutable` setting. It will make all values returned from the context immutable, allowing you to persist them anywhere. Of course, this comes at the cost of performance.
|
Alternatively, you can enable the `Immutable` setting. This makes all values returned from the context immutable, allowing you to persist them anywhere. Note that this comes at the cost of performance.
|
||||||
|
|
||||||
```go
|
```go
|
||||||
app := fiber.New(fiber.Config{
|
app := fiber.New(fiber.Config{
|
||||||
|
@ -69,11 +69,11 @@ app := fiber.New(fiber.Config{
|
||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
For more information, please check [**\#426**](https://github.com/gofiber/fiber/issues/426), [**\#185**](https://github.com/gofiber/fiber/issues/185) and [**\#3012**](https://github.com/gofiber/fiber/issues/3012).
|
For more information, please refer to [#426](https://github.com/gofiber/fiber/issues/426), [#185](https://github.com/gofiber/fiber/issues/185), and [#3012](https://github.com/gofiber/fiber/issues/3012).
|
||||||
|
|
||||||
### Hello, World
|
### Hello, World
|
||||||
|
|
||||||
Embedded below is essentially the most straightforward **Fiber** app you can create:
|
Below is the most straightforward **Fiber** application you can create:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
package main
|
package main
|
||||||
|
@ -95,15 +95,15 @@ func main() {
|
||||||
go run server.go
|
go run server.go
|
||||||
```
|
```
|
||||||
|
|
||||||
Browse to `http://localhost:3000` and you should see `Hello, World!` on the page.
|
Browse to `http://localhost:3000` and you should see `Hello, World!` displayed on the page.
|
||||||
|
|
||||||
### Basic routing
|
### Basic Routing
|
||||||
|
|
||||||
Routing refers to determining how an application responds to a client request to a particular endpoint, which is a URI (or path) and a specific HTTP request method (`GET`, `PUT`, `POST`, etc.).
|
Routing determines how an application responds to a client request to a particular endpoint, which is a URI (or path) and a specific HTTP request method (`GET`, `PUT`, `POST`, etc.).
|
||||||
|
|
||||||
Each route can have **multiple handler functions** that are executed when the route is matched.
|
Each route can have **multiple handler functions** that are executed when the route is matched.
|
||||||
|
|
||||||
Route definition takes the following structures:
|
Route definitions follow the structure below:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
// Function signature
|
// Function signature
|
||||||
|
@ -115,10 +115,10 @@ app.Method(path string, ...func(fiber.Ctx) error)
|
||||||
- `path` is a virtual path on the server
|
- `path` is a virtual path on the server
|
||||||
- `func(fiber.Ctx) error` is a callback function containing the [Context](https://docs.gofiber.io/api/ctx) executed when the route is matched
|
- `func(fiber.Ctx) error` is a callback function containing the [Context](https://docs.gofiber.io/api/ctx) executed when the route is matched
|
||||||
|
|
||||||
#### Simple route
|
#### Simple Route
|
||||||
|
|
||||||
```go
|
```go
|
||||||
// Respond with "Hello, World!" on root path, "/"
|
// Respond with "Hello, World!" on root path "/"
|
||||||
app.Get("/", func(c fiber.Ctx) error {
|
app.Get("/", func(c fiber.Ctx) error {
|
||||||
return c.SendString("Hello, World!")
|
return c.SendString("Hello, World!")
|
||||||
})
|
})
|
||||||
|
@ -131,11 +131,11 @@ app.Get("/", func(c fiber.Ctx) error {
|
||||||
|
|
||||||
app.Get("/:value", func(c fiber.Ctx) error {
|
app.Get("/:value", func(c fiber.Ctx) error {
|
||||||
return c.SendString("value: " + c.Params("value"))
|
return c.SendString("value: " + c.Params("value"))
|
||||||
// => Get request with value: hello world
|
// => Response: "value: hello world"
|
||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Optional parameter
|
#### Optional Parameter
|
||||||
|
|
||||||
```go
|
```go
|
||||||
// GET http://localhost:3000/john
|
// GET http://localhost:3000/john
|
||||||
|
@ -143,9 +143,10 @@ app.Get("/:value", func(c fiber.Ctx) error {
|
||||||
app.Get("/:name?", func(c fiber.Ctx) error {
|
app.Get("/:name?", func(c fiber.Ctx) error {
|
||||||
if c.Params("name") != "" {
|
if c.Params("name") != "" {
|
||||||
return c.SendString("Hello " + c.Params("name"))
|
return c.SendString("Hello " + c.Params("name"))
|
||||||
// => Hello john
|
// => Response: "Hello john"
|
||||||
}
|
}
|
||||||
return c.SendString("Where is john?")
|
return c.SendString("Where is john?")
|
||||||
|
// => Response: "Where is john?"
|
||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -156,27 +157,33 @@ app.Get("/:name?", func(c fiber.Ctx) error {
|
||||||
|
|
||||||
app.Get("/api/*", func(c fiber.Ctx) error {
|
app.Get("/api/*", func(c fiber.Ctx) error {
|
||||||
return c.SendString("API path: " + c.Params("*"))
|
return c.SendString("API path: " + c.Params("*"))
|
||||||
// => API path: user/john
|
// => Response: "API path: user/john"
|
||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
### Static files
|
### Static Files
|
||||||
|
|
||||||
To serve static files such as **images**, **CSS**, and **JavaScript** files, replace your function handler with a file or directory string.
|
To serve static files such as **images**, **CSS**, and **JavaScript** files, use the `Static` method with a directory path. For more information, refer to the [static middleware](./middleware/static.md).
|
||||||
You can check out [static middleware](./middleware/static.md) for more information.
|
|
||||||
Function signature:
|
|
||||||
|
|
||||||
Use the following code to serve files in a directory named `./public`:
|
Use the following code to serve files in a directory named `./public`:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
app := fiber.New()
|
package main
|
||||||
|
|
||||||
app.Get("/*", static.New("./public"))
|
import (
|
||||||
|
"github.com/gofiber/fiber/v3"
|
||||||
|
)
|
||||||
|
|
||||||
app.Listen(":3000")
|
func main() {
|
||||||
|
app := fiber.New()
|
||||||
|
|
||||||
|
app.Static("/", "./public")
|
||||||
|
|
||||||
|
app.Listen(":3000")
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Now, you can load the files that are in the `./public` directory:
|
Now, you can access the files in the `./public` directory via your browser:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
http://localhost:3000/hello.html
|
http://localhost:3000/hello.html
|
||||||
|
|
|
@ -8,7 +8,7 @@ There exist two distinct implementations of timeout middleware [Fiber](https://g
|
||||||
|
|
||||||
## New
|
## New
|
||||||
|
|
||||||
As a `fiber.Handler` wrapper, it creates a context with `context.WithTimeout` and pass it in `UserContext`.
|
As a `fiber.Handler` wrapper, it creates a context with `context.WithTimeout` which is then used with `c.Context()`.
|
||||||
|
|
||||||
If the context passed executions (eg. DB ops, Http calls) takes longer than the given duration to return, the timeout error is set and forwarded to the centralized `ErrorHandler`.
|
If the context passed executions (eg. DB ops, Http calls) takes longer than the given duration to return, the timeout error is set and forwarded to the centralized `ErrorHandler`.
|
||||||
|
|
||||||
|
@ -38,7 +38,7 @@ func main() {
|
||||||
app := fiber.New()
|
app := fiber.New()
|
||||||
h := func(c fiber.Ctx) error {
|
h := func(c fiber.Ctx) error {
|
||||||
sleepTime, _ := time.ParseDuration(c.Params("sleepTime") + "ms")
|
sleepTime, _ := time.ParseDuration(c.Params("sleepTime") + "ms")
|
||||||
if err := sleepWithContext(c.UserContext(), sleepTime); err != nil {
|
if err := sleepWithContext(c.Context(), sleepTime); err != nil {
|
||||||
return fmt.Errorf("%w: execution error", err)
|
return fmt.Errorf("%w: execution error", err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -84,7 +84,7 @@ func main() {
|
||||||
app := fiber.New()
|
app := fiber.New()
|
||||||
h := func(c fiber.Ctx) error {
|
h := func(c fiber.Ctx) error {
|
||||||
sleepTime, _ := time.ParseDuration(c.Params("sleepTime") + "ms")
|
sleepTime, _ := time.ParseDuration(c.Params("sleepTime") + "ms")
|
||||||
if err := sleepWithContextWithCustomError(c.UserContext(), sleepTime); err != nil {
|
if err := sleepWithContextWithCustomError(c.Context(), sleepTime); err != nil {
|
||||||
return fmt.Errorf("%w: execution error", err)
|
return fmt.Errorf("%w: execution error", err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -116,7 +116,7 @@ func main() {
|
||||||
db, _ := gorm.Open(postgres.Open("postgres://localhost/foodb"), &gorm.Config{})
|
db, _ := gorm.Open(postgres.Open("postgres://localhost/foodb"), &gorm.Config{})
|
||||||
|
|
||||||
handler := func(ctx fiber.Ctx) error {
|
handler := func(ctx fiber.Ctx) error {
|
||||||
tran := db.WithContext(ctx.UserContext()).Begin()
|
tran := db.WithContext(ctx.Context()).Begin()
|
||||||
|
|
||||||
if tran = tran.Exec("SELECT pg_sleep(50)"); tran.Error != nil {
|
if tran = tran.Exec("SELECT pg_sleep(50)"); tran.Error != nil {
|
||||||
return tran.Error
|
return tran.Error
|
||||||
|
|
|
@ -229,6 +229,9 @@ DRAFT section
|
||||||
- Format -> Param: body interface{} -> handlers ...ResFmt
|
- Format -> Param: body interface{} -> handlers ...ResFmt
|
||||||
- Redirect -> c.Redirect().To()
|
- Redirect -> c.Redirect().To()
|
||||||
- SendFile now supports different configurations using the config parameter.
|
- SendFile now supports different configurations using the config parameter.
|
||||||
|
- Context has been renamed to RequestCtx which corresponds to the FastHTTP Request Context.
|
||||||
|
- UserContext has been renamed to Context which returns a context.Context object.
|
||||||
|
- SetUserContext has been renamed to SetContext.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,7 @@ func HTTPHandlerFunc(h http.HandlerFunc) fiber.Handler {
|
||||||
func HTTPHandler(h http.Handler) fiber.Handler {
|
func HTTPHandler(h http.Handler) fiber.Handler {
|
||||||
return func(c fiber.Ctx) error {
|
return func(c fiber.Ctx) error {
|
||||||
handler := fasthttpadaptor.NewFastHTTPHandler(h)
|
handler := fasthttpadaptor.NewFastHTTPHandler(h)
|
||||||
handler(c.Context())
|
handler(c.RequestCtx())
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -43,7 +43,7 @@ func HTTPHandler(h http.Handler) fiber.Handler {
|
||||||
// forServer should be set to true when the http.Request is going to be passed to a http.Handler.
|
// forServer should be set to true when the http.Request is going to be passed to a http.Handler.
|
||||||
func ConvertRequest(c fiber.Ctx, forServer bool) (*http.Request, error) {
|
func ConvertRequest(c fiber.Ctx, forServer bool) (*http.Request, error) {
|
||||||
var req http.Request
|
var req http.Request
|
||||||
if err := fasthttpadaptor.ConvertRequest(c.Context(), &req, forServer); err != nil {
|
if err := fasthttpadaptor.ConvertRequest(c.RequestCtx(), &req, forServer); err != nil {
|
||||||
return nil, err //nolint:wrapcheck // This must not be wrapped
|
return nil, err //nolint:wrapcheck // This must not be wrapped
|
||||||
}
|
}
|
||||||
return &req, nil
|
return &req, nil
|
||||||
|
@ -108,7 +108,7 @@ func HTTPMiddleware(mw func(http.Handler) http.Handler) fiber.Handler {
|
||||||
c.Request().Header.Set(key, v)
|
c.Request().Header.Set(key, v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CopyContextToFiberContext(r.Context(), c.Context())
|
CopyContextToFiberContext(r.Context(), c.RequestCtx())
|
||||||
})
|
})
|
||||||
|
|
||||||
if err := HTTPHandler(mw(nextHandler))(c); err != nil {
|
if err := HTTPHandler(mw(nextHandler))(c); err != nil {
|
||||||
|
|
|
@ -162,7 +162,7 @@ func Test_HTTPMiddleware(t *testing.T) {
|
||||||
app := fiber.New()
|
app := fiber.New()
|
||||||
app.Use(HTTPMiddleware(nethttpMW))
|
app.Use(HTTPMiddleware(nethttpMW))
|
||||||
app.Post("/", func(c fiber.Ctx) error {
|
app.Post("/", func(c fiber.Ctx) error {
|
||||||
value := c.Context().Value(TestContextKey)
|
value := c.RequestCtx().Value(TestContextKey)
|
||||||
val, ok := value.(string)
|
val, ok := value.(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
t.Error("unexpected error on type-assertion")
|
t.Error("unexpected error on type-assertion")
|
||||||
|
@ -170,7 +170,7 @@ func Test_HTTPMiddleware(t *testing.T) {
|
||||||
if value != nil {
|
if value != nil {
|
||||||
c.Set("context_okay", val)
|
c.Set("context_okay", val)
|
||||||
}
|
}
|
||||||
value = c.Context().Value(TestContextSecondKey)
|
value = c.RequestCtx().Value(TestContextSecondKey)
|
||||||
if value != nil {
|
if value != nil {
|
||||||
val, ok := value.(string)
|
val, ok := value.(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@ -316,12 +316,12 @@ func testFiberToHandlerFunc(t *testing.T, checkDefaultPort bool, app ...*fiber.A
|
||||||
fiberH := func(c fiber.Ctx) error {
|
fiberH := func(c fiber.Ctx) error {
|
||||||
callsCount++
|
callsCount++
|
||||||
require.Equal(t, expectedMethod, c.Method(), "Method")
|
require.Equal(t, expectedMethod, c.Method(), "Method")
|
||||||
require.Equal(t, expectedRequestURI, string(c.Context().RequestURI()), "RequestURI")
|
require.Equal(t, expectedRequestURI, string(c.RequestCtx().RequestURI()), "RequestURI")
|
||||||
require.Equal(t, expectedContentLength, c.Context().Request.Header.ContentLength(), "ContentLength")
|
require.Equal(t, expectedContentLength, c.RequestCtx().Request.Header.ContentLength(), "ContentLength")
|
||||||
require.Equal(t, expectedHost, c.Hostname(), "Host")
|
require.Equal(t, expectedHost, c.Hostname(), "Host")
|
||||||
require.Equal(t, expectedHost, string(c.Request().Header.Host()), "Host")
|
require.Equal(t, expectedHost, string(c.Request().Header.Host()), "Host")
|
||||||
require.Equal(t, "http://"+expectedHost, c.BaseURL(), "BaseURL")
|
require.Equal(t, "http://"+expectedHost, c.BaseURL(), "BaseURL")
|
||||||
require.Equal(t, expectedRemoteAddr, c.Context().RemoteAddr().String(), "RemoteAddr")
|
require.Equal(t, expectedRemoteAddr, c.RequestCtx().RemoteAddr().String(), "RemoteAddr")
|
||||||
|
|
||||||
body := string(c.Body())
|
body := string(c.Body())
|
||||||
require.Equal(t, expectedBody, body, "Body")
|
require.Equal(t, expectedBody, body, "Body")
|
||||||
|
@ -392,8 +392,8 @@ func Test_FiberHandler_RequestNilBody(t *testing.T) {
|
||||||
fiberH := func(c fiber.Ctx) error {
|
fiberH := func(c fiber.Ctx) error {
|
||||||
callsCount++
|
callsCount++
|
||||||
require.Equal(t, expectedMethod, c.Method(), "Method")
|
require.Equal(t, expectedMethod, c.Method(), "Method")
|
||||||
require.Equal(t, expectedRequestURI, string(c.Context().RequestURI()), "RequestURI")
|
require.Equal(t, expectedRequestURI, string(c.RequestCtx().RequestURI()), "RequestURI")
|
||||||
require.Equal(t, expectedContentLength, c.Context().Request.Header.ContentLength(), "ContentLength")
|
require.Equal(t, expectedContentLength, c.RequestCtx().Request.Header.ContentLength(), "ContentLength")
|
||||||
|
|
||||||
_, err := c.Write([]byte("request body is nil"))
|
_, err := c.Write([]byte("request body is nil"))
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -894,7 +894,7 @@ func Test_Cache_MaxBytesSizes(t *testing.T) {
|
||||||
}))
|
}))
|
||||||
|
|
||||||
app.Get("/*", func(c fiber.Ctx) error {
|
app.Get("/*", func(c fiber.Ctx) error {
|
||||||
path := c.Context().URI().LastPathSegment()
|
path := c.RequestCtx().URI().LastPathSegment()
|
||||||
size, err := strconv.Atoi(string(path))
|
size, err := strconv.Atoi(string(path))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
return c.Send(make([]byte, size))
|
return c.Send(make([]byte, size))
|
||||||
|
|
|
@ -56,7 +56,7 @@ func New(config ...Config) fiber.Handler {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compress response
|
// Compress response
|
||||||
compressor(c.Context())
|
compressor(c.RequestCtx())
|
||||||
|
|
||||||
// Return from handler
|
// Return from handler
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -80,7 +80,7 @@ func New(config ...Config) fiber.Handler {
|
||||||
// Check if server's ETag is weak
|
// Check if server's ETag is weak
|
||||||
if bytes.Equal(clientEtag[2:], etag) || bytes.Equal(clientEtag[2:], etag[2:]) {
|
if bytes.Equal(clientEtag[2:], etag) || bytes.Equal(clientEtag[2:], etag[2:]) {
|
||||||
// W/1 == 1 || W/1 == W/1
|
// W/1 == 1 || W/1 == W/1
|
||||||
c.Context().ResetBody()
|
c.RequestCtx().ResetBody()
|
||||||
|
|
||||||
return c.SendStatus(fiber.StatusNotModified)
|
return c.SendStatus(fiber.StatusNotModified)
|
||||||
}
|
}
|
||||||
|
@ -92,7 +92,7 @@ func New(config ...Config) fiber.Handler {
|
||||||
|
|
||||||
if bytes.Contains(clientEtag, etag) {
|
if bytes.Contains(clientEtag, etag) {
|
||||||
// 1 == 1
|
// 1 == 1
|
||||||
c.Context().ResetBody()
|
c.RequestCtx().ResetBody()
|
||||||
|
|
||||||
return c.SendStatus(fiber.StatusNotModified)
|
return c.SendStatus(fiber.StatusNotModified)
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,7 @@ func New(config ...Config) fiber.Handler {
|
||||||
return c.Next()
|
return c.Next()
|
||||||
}
|
}
|
||||||
if path == "/debug/vars" {
|
if path == "/debug/vars" {
|
||||||
expvarhandler.ExpvarHandler(c.Context())
|
expvarhandler.ExpvarHandler(c.RequestCtx())
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -51,7 +51,7 @@ func New(config ...Config) fiber.Handler {
|
||||||
|
|
||||||
for header, vals := range res.Headers {
|
for header, vals := range res.Headers {
|
||||||
for _, val := range vals {
|
for _, val := range vals {
|
||||||
c.Context().Response.Header.Add(header, val)
|
c.RequestCtx().Response.Header.Add(header, val)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -632,7 +632,7 @@ func Test_Logger_ByteSent_Streaming(t *testing.T) {
|
||||||
app.Get("/", func(c fiber.Ctx) error {
|
app.Get("/", func(c fiber.Ctx) error {
|
||||||
c.Set("Connection", "keep-alive")
|
c.Set("Connection", "keep-alive")
|
||||||
c.Set("Transfer-Encoding", "chunked")
|
c.Set("Transfer-Encoding", "chunked")
|
||||||
c.Context().SetBodyStreamWriter(func(w *bufio.Writer) {
|
c.RequestCtx().SetBodyStreamWriter(func(w *bufio.Writer) {
|
||||||
var i int
|
var i int
|
||||||
for {
|
for {
|
||||||
i++
|
i++
|
||||||
|
@ -803,7 +803,7 @@ func Benchmark_Logger(b *testing.B) {
|
||||||
app.Get("/", func(c fiber.Ctx) error {
|
app.Get("/", func(c fiber.Ctx) error {
|
||||||
c.Set("Connection", "keep-alive")
|
c.Set("Connection", "keep-alive")
|
||||||
c.Set("Transfer-Encoding", "chunked")
|
c.Set("Transfer-Encoding", "chunked")
|
||||||
c.Context().SetBodyStreamWriter(func(w *bufio.Writer) {
|
c.RequestCtx().SetBodyStreamWriter(func(w *bufio.Writer) {
|
||||||
var i int
|
var i int
|
||||||
for {
|
for {
|
||||||
i++
|
i++
|
||||||
|
@ -958,7 +958,7 @@ func Benchmark_Logger_Parallel(b *testing.B) {
|
||||||
app.Get("/", func(c fiber.Ctx) error {
|
app.Get("/", func(c fiber.Ctx) error {
|
||||||
c.Set("Connection", "keep-alive")
|
c.Set("Connection", "keep-alive")
|
||||||
c.Set("Transfer-Encoding", "chunked")
|
c.Set("Transfer-Encoding", "chunked")
|
||||||
c.Context().SetBodyStreamWriter(func(w *bufio.Writer) {
|
c.RequestCtx().SetBodyStreamWriter(func(w *bufio.Writer) {
|
||||||
var i int
|
var i int
|
||||||
for {
|
for {
|
||||||
i++
|
i++
|
||||||
|
|
|
@ -48,27 +48,27 @@ func New(config ...Config) fiber.Handler {
|
||||||
// Switch on trimmed path against constant strings
|
// Switch on trimmed path against constant strings
|
||||||
switch path {
|
switch path {
|
||||||
case "/":
|
case "/":
|
||||||
pprofIndex(c.Context())
|
pprofIndex(c.RequestCtx())
|
||||||
case "/cmdline":
|
case "/cmdline":
|
||||||
pprofCmdline(c.Context())
|
pprofCmdline(c.RequestCtx())
|
||||||
case "/profile":
|
case "/profile":
|
||||||
pprofProfile(c.Context())
|
pprofProfile(c.RequestCtx())
|
||||||
case "/symbol":
|
case "/symbol":
|
||||||
pprofSymbol(c.Context())
|
pprofSymbol(c.RequestCtx())
|
||||||
case "/trace":
|
case "/trace":
|
||||||
pprofTrace(c.Context())
|
pprofTrace(c.RequestCtx())
|
||||||
case "/allocs":
|
case "/allocs":
|
||||||
pprofAllocs(c.Context())
|
pprofAllocs(c.RequestCtx())
|
||||||
case "/block":
|
case "/block":
|
||||||
pprofBlock(c.Context())
|
pprofBlock(c.RequestCtx())
|
||||||
case "/goroutine":
|
case "/goroutine":
|
||||||
pprofGoroutine(c.Context())
|
pprofGoroutine(c.RequestCtx())
|
||||||
case "/heap":
|
case "/heap":
|
||||||
pprofHeap(c.Context())
|
pprofHeap(c.RequestCtx())
|
||||||
case "/mutex":
|
case "/mutex":
|
||||||
pprofMutex(c.Context())
|
pprofMutex(c.RequestCtx())
|
||||||
case "/threadcreate":
|
case "/threadcreate":
|
||||||
pprofThreadcreate(c.Context())
|
pprofThreadcreate(c.RequestCtx())
|
||||||
default:
|
default:
|
||||||
// pprof index only works with trailing slash
|
// pprof index only works with trailing slash
|
||||||
if strings.HasSuffix(path, "/") {
|
if strings.HasSuffix(path, "/") {
|
||||||
|
|
|
@ -30,7 +30,7 @@ func New(config ...Config) fiber.Handler {
|
||||||
for k, v := range cfg.rulesRegex {
|
for k, v := range cfg.rulesRegex {
|
||||||
replacer := captureTokens(k, c.Path())
|
replacer := captureTokens(k, c.Path())
|
||||||
if replacer != nil {
|
if replacer != nil {
|
||||||
queryString := string(c.Context().QueryArgs().QueryString())
|
queryString := string(c.RequestCtx().QueryArgs().QueryString())
|
||||||
if queryString != "" {
|
if queryString != "" {
|
||||||
queryString = "?" + queryString
|
queryString = "?" + queryString
|
||||||
}
|
}
|
||||||
|
|
|
@ -114,7 +114,7 @@ func New(root string, cfg ...Config) fiber.Handler {
|
||||||
})
|
})
|
||||||
|
|
||||||
// Serve file
|
// Serve file
|
||||||
fileHandler(c.Context())
|
fileHandler(c.RequestCtx())
|
||||||
|
|
||||||
// Sets the response Content-Disposition header to attachment if the Download option is true
|
// Sets the response Content-Disposition header to attachment if the Download option is true
|
||||||
if config.Download {
|
if config.Download {
|
||||||
|
@ -122,11 +122,11 @@ func New(root string, cfg ...Config) fiber.Handler {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return request if found and not forbidden
|
// Return request if found and not forbidden
|
||||||
status := c.Context().Response.StatusCode()
|
status := c.RequestCtx().Response.StatusCode()
|
||||||
|
|
||||||
if status != fiber.StatusNotFound && status != fiber.StatusForbidden {
|
if status != fiber.StatusNotFound && status != fiber.StatusForbidden {
|
||||||
if len(cacheControlValue) > 0 {
|
if len(cacheControlValue) > 0 {
|
||||||
c.Context().Response.Header.Set(fiber.HeaderCacheControl, cacheControlValue)
|
c.RequestCtx().Response.Header.Set(fiber.HeaderCacheControl, cacheControlValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.ModifyResponse != nil {
|
if config.ModifyResponse != nil {
|
||||||
|
@ -142,9 +142,9 @@ func New(root string, cfg ...Config) fiber.Handler {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset response to default
|
// Reset response to default
|
||||||
c.Context().SetContentType("") // Issue #420
|
c.RequestCtx().SetContentType("") // Issue #420
|
||||||
c.Context().Response.SetStatusCode(fiber.StatusOK)
|
c.RequestCtx().Response.SetStatusCode(fiber.StatusOK)
|
||||||
c.Context().Response.SetBodyString("")
|
c.RequestCtx().Response.SetBodyString("")
|
||||||
|
|
||||||
// Next middleware
|
// Next middleware
|
||||||
return c.Next()
|
return c.Next()
|
||||||
|
|
|
@ -11,9 +11,9 @@ import (
|
||||||
// New implementation of timeout middleware. Set custom errors(context.DeadlineExceeded vs) for get fiber.ErrRequestTimeout response.
|
// New implementation of timeout middleware. Set custom errors(context.DeadlineExceeded vs) for get fiber.ErrRequestTimeout response.
|
||||||
func New(h fiber.Handler, t time.Duration, tErrs ...error) fiber.Handler {
|
func New(h fiber.Handler, t time.Duration, tErrs ...error) fiber.Handler {
|
||||||
return func(ctx fiber.Ctx) error {
|
return func(ctx fiber.Ctx) error {
|
||||||
timeoutContext, cancel := context.WithTimeout(ctx.UserContext(), t)
|
timeoutContext, cancel := context.WithTimeout(ctx.Context(), t)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
ctx.SetUserContext(timeoutContext)
|
ctx.SetContext(timeoutContext)
|
||||||
if err := h(ctx); err != nil {
|
if err := h(ctx); err != nil {
|
||||||
if errors.Is(err, context.DeadlineExceeded) {
|
if errors.Is(err, context.DeadlineExceeded) {
|
||||||
return fiber.ErrRequestTimeout
|
return fiber.ErrRequestTimeout
|
||||||
|
|
|
@ -20,7 +20,7 @@ func Test_WithContextTimeout(t *testing.T) {
|
||||||
h := New(func(c fiber.Ctx) error {
|
h := New(func(c fiber.Ctx) error {
|
||||||
sleepTime, err := time.ParseDuration(c.Params("sleepTime") + "ms")
|
sleepTime, err := time.ParseDuration(c.Params("sleepTime") + "ms")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
if err := sleepWithContext(c.UserContext(), sleepTime, context.DeadlineExceeded); err != nil {
|
if err := sleepWithContext(c.Context(), sleepTime, context.DeadlineExceeded); err != nil {
|
||||||
return fmt.Errorf("%w: l2 wrap", fmt.Errorf("%w: l1 wrap ", err))
|
return fmt.Errorf("%w: l2 wrap", fmt.Errorf("%w: l1 wrap ", err))
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -52,7 +52,7 @@ func Test_WithContextTimeoutWithCustomError(t *testing.T) {
|
||||||
h := New(func(c fiber.Ctx) error {
|
h := New(func(c fiber.Ctx) error {
|
||||||
sleepTime, err := time.ParseDuration(c.Params("sleepTime") + "ms")
|
sleepTime, err := time.ParseDuration(c.Params("sleepTime") + "ms")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
if err := sleepWithContext(c.UserContext(), sleepTime, ErrFooTimeOut); err != nil {
|
if err := sleepWithContext(c.Context(), sleepTime, ErrFooTimeOut); err != nil {
|
||||||
return fmt.Errorf("%w: execution error", err)
|
return fmt.Errorf("%w: execution error", err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -141,7 +141,7 @@ func (r *Redirect) With(key, value string, level ...uint8) *Redirect {
|
||||||
// You can get them by using: Redirect().OldInputs(), Redirect().OldInput()
|
// You can get them by using: Redirect().OldInputs(), Redirect().OldInput()
|
||||||
func (r *Redirect) WithInput() *Redirect {
|
func (r *Redirect) WithInput() *Redirect {
|
||||||
// Get content-type
|
// Get content-type
|
||||||
ctype := utils.ToLower(utils.UnsafeString(r.c.Context().Request.Header.ContentType()))
|
ctype := utils.ToLower(utils.UnsafeString(r.c.RequestCtx().Request.Header.ContentType()))
|
||||||
ctype = binder.FilterFlags(utils.ParseVendorSpecificContentType(ctype))
|
ctype = binder.FilterFlags(utils.ParseVendorSpecificContentType(ctype))
|
||||||
|
|
||||||
oldInput := make(map[string]string)
|
oldInput := make(map[string]string)
|
||||||
|
|
|
@ -42,7 +42,7 @@ func Test_Redirect_To_WithFlashMessages(t *testing.T) {
|
||||||
require.Equal(t, 302, c.Response().StatusCode())
|
require.Equal(t, 302, c.Response().StatusCode())
|
||||||
require.Equal(t, "http://example.com", string(c.Response().Header.Peek(HeaderLocation)))
|
require.Equal(t, "http://example.com", string(c.Response().Header.Peek(HeaderLocation)))
|
||||||
|
|
||||||
c.Context().Request.Header.Set(HeaderCookie, c.GetRespHeader(HeaderSetCookie)) // necessary for testing
|
c.RequestCtx().Request.Header.Set(HeaderCookie, c.GetRespHeader(HeaderSetCookie)) // necessary for testing
|
||||||
|
|
||||||
var msgs redirectionMsgs
|
var msgs redirectionMsgs
|
||||||
_, err = msgs.UnmarshalMsg([]byte(c.Cookies(FlashCookieName)))
|
_, err = msgs.UnmarshalMsg([]byte(c.Cookies(FlashCookieName)))
|
||||||
|
@ -185,7 +185,7 @@ func Test_Redirect_Back_WithFlashMessages(t *testing.T) {
|
||||||
require.Equal(t, 302, c.Response().StatusCode())
|
require.Equal(t, 302, c.Response().StatusCode())
|
||||||
require.Equal(t, "/", string(c.Response().Header.Peek(HeaderLocation)))
|
require.Equal(t, "/", string(c.Response().Header.Peek(HeaderLocation)))
|
||||||
|
|
||||||
c.Context().Request.Header.Set(HeaderCookie, c.GetRespHeader(HeaderSetCookie)) // necessary for testing
|
c.RequestCtx().Request.Header.Set(HeaderCookie, c.GetRespHeader(HeaderSetCookie)) // necessary for testing
|
||||||
|
|
||||||
var msgs redirectionMsgs
|
var msgs redirectionMsgs
|
||||||
_, err = msgs.UnmarshalMsg([]byte(c.Cookies(FlashCookieName)))
|
_, err = msgs.UnmarshalMsg([]byte(c.Cookies(FlashCookieName)))
|
||||||
|
@ -236,7 +236,7 @@ func Test_Redirect_Route_WithFlashMessages(t *testing.T) {
|
||||||
require.Equal(t, 302, c.Response().StatusCode())
|
require.Equal(t, 302, c.Response().StatusCode())
|
||||||
require.Equal(t, "/user", string(c.Response().Header.Peek(HeaderLocation)))
|
require.Equal(t, "/user", string(c.Response().Header.Peek(HeaderLocation)))
|
||||||
|
|
||||||
c.Context().Request.Header.Set(HeaderCookie, c.GetRespHeader(HeaderSetCookie)) // necessary for testing
|
c.RequestCtx().Request.Header.Set(HeaderCookie, c.GetRespHeader(HeaderSetCookie)) // necessary for testing
|
||||||
|
|
||||||
var msgs redirectionMsgs
|
var msgs redirectionMsgs
|
||||||
_, err = msgs.UnmarshalMsg([]byte(c.Cookies(FlashCookieName)))
|
_, err = msgs.UnmarshalMsg([]byte(c.Cookies(FlashCookieName)))
|
||||||
|
@ -273,7 +273,7 @@ func Test_Redirect_Route_WithOldInput(t *testing.T) {
|
||||||
require.Equal(t, 302, c.Response().StatusCode())
|
require.Equal(t, 302, c.Response().StatusCode())
|
||||||
require.Equal(t, "/user", string(c.Response().Header.Peek(HeaderLocation)))
|
require.Equal(t, "/user", string(c.Response().Header.Peek(HeaderLocation)))
|
||||||
|
|
||||||
c.Context().Request.Header.Set(HeaderCookie, c.GetRespHeader(HeaderSetCookie)) // necessary for testing
|
c.RequestCtx().Request.Header.Set(HeaderCookie, c.GetRespHeader(HeaderSetCookie)) // necessary for testing
|
||||||
|
|
||||||
var msgs redirectionMsgs
|
var msgs redirectionMsgs
|
||||||
_, err = msgs.UnmarshalMsg([]byte(c.Cookies(FlashCookieName)))
|
_, err = msgs.UnmarshalMsg([]byte(c.Cookies(FlashCookieName)))
|
||||||
|
@ -309,7 +309,7 @@ func Test_Redirect_Route_WithOldInput(t *testing.T) {
|
||||||
require.Equal(t, 302, c.Response().StatusCode())
|
require.Equal(t, 302, c.Response().StatusCode())
|
||||||
require.Equal(t, "/user", string(c.Response().Header.Peek(HeaderLocation)))
|
require.Equal(t, "/user", string(c.Response().Header.Peek(HeaderLocation)))
|
||||||
|
|
||||||
c.Context().Request.Header.Set(HeaderCookie, c.GetRespHeader(HeaderSetCookie)) // necessary for testing
|
c.RequestCtx().Request.Header.Set(HeaderCookie, c.GetRespHeader(HeaderSetCookie)) // necessary for testing
|
||||||
|
|
||||||
var msgs redirectionMsgs
|
var msgs redirectionMsgs
|
||||||
_, err = msgs.UnmarshalMsg([]byte(c.Cookies(FlashCookieName)))
|
_, err = msgs.UnmarshalMsg([]byte(c.Cookies(FlashCookieName)))
|
||||||
|
@ -353,7 +353,7 @@ func Test_Redirect_Route_WithOldInput(t *testing.T) {
|
||||||
require.Equal(t, 302, c.Response().StatusCode())
|
require.Equal(t, 302, c.Response().StatusCode())
|
||||||
require.Equal(t, "/user", string(c.Response().Header.Peek(HeaderLocation)))
|
require.Equal(t, "/user", string(c.Response().Header.Peek(HeaderLocation)))
|
||||||
|
|
||||||
c.Context().Request.Header.Set(HeaderCookie, c.GetRespHeader(HeaderSetCookie)) // necessary for testing
|
c.RequestCtx().Request.Header.Set(HeaderCookie, c.GetRespHeader(HeaderSetCookie)) // necessary for testing
|
||||||
|
|
||||||
var msgs redirectionMsgs
|
var msgs redirectionMsgs
|
||||||
_, err = msgs.UnmarshalMsg([]byte(c.Cookies(FlashCookieName)))
|
_, err = msgs.UnmarshalMsg([]byte(c.Cookies(FlashCookieName)))
|
||||||
|
@ -538,7 +538,7 @@ func Benchmark_Redirect_Route_WithFlashMessages(b *testing.B) {
|
||||||
require.Equal(b, 302, c.Response().StatusCode())
|
require.Equal(b, 302, c.Response().StatusCode())
|
||||||
require.Equal(b, "/user", string(c.Response().Header.Peek(HeaderLocation)))
|
require.Equal(b, "/user", string(c.Response().Header.Peek(HeaderLocation)))
|
||||||
|
|
||||||
c.Context().Request.Header.Set(HeaderCookie, c.GetRespHeader(HeaderSetCookie)) // necessary for testing
|
c.RequestCtx().Request.Header.Set(HeaderCookie, c.GetRespHeader(HeaderSetCookie)) // necessary for testing
|
||||||
|
|
||||||
var msgs redirectionMsgs
|
var msgs redirectionMsgs
|
||||||
_, err = msgs.UnmarshalMsg([]byte(c.Cookies(FlashCookieName)))
|
_, err = msgs.UnmarshalMsg([]byte(c.Cookies(FlashCookieName)))
|
||||||
|
@ -629,7 +629,7 @@ func Benchmark_Redirect_processFlashMessages(b *testing.B) {
|
||||||
c.Redirect().processFlashMessages()
|
c.Redirect().processFlashMessages()
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Context().Request.Header.Set(HeaderCookie, c.GetRespHeader(HeaderSetCookie)) // necessary for testing
|
c.RequestCtx().Request.Header.Set(HeaderCookie, c.GetRespHeader(HeaderSetCookie)) // necessary for testing
|
||||||
|
|
||||||
var msgs redirectionMsgs
|
var msgs redirectionMsgs
|
||||||
_, err := msgs.UnmarshalMsg([]byte(c.Cookies(FlashCookieName)))
|
_, err := msgs.UnmarshalMsg([]byte(c.Cookies(FlashCookieName)))
|
||||||
|
|
Loading…
Reference in New Issue