Merge branch 'main' into update-redirect

gaby/issue3095
Juan Calderon-Perez 2024-11-13 21:00:46 -05:00 committed by GitHub
commit 9d79488dec
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
24 changed files with 161 additions and 152 deletions

10
bind.go
View File

@ -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

View File

@ -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
View File

@ -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

View File

@ -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.

View File

@ -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)
} }

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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.
--- ---

View File

@ -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 {

View File

@ -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

View File

@ -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))

View File

@ -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

View File

@ -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)
} }

View File

@ -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
} }

View File

@ -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)
} }
} }

View File

@ -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++

View File

@ -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, "/") {

View File

@ -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
} }

View File

@ -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()

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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)))