Adding upstream version 2.52.6.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
a960158181
commit
6d002e9543
441 changed files with 95392 additions and 0 deletions
9
docs/api/middleware/_category_.json
Normal file
9
docs/api/middleware/_category_.json
Normal file
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"label": "🧬 Middleware",
|
||||
"position": 7,
|
||||
"collapsed": true,
|
||||
"link": {
|
||||
"type": "generated-index",
|
||||
"description": "Middleware is a function chained in the HTTP request cycle with access to the Context which it uses to perform a specific action, for example, logging every request or enabling CORS."
|
||||
}
|
||||
}
|
169
docs/api/middleware/adaptor.md
Normal file
169
docs/api/middleware/adaptor.md
Normal file
|
@ -0,0 +1,169 @@
|
|||
---
|
||||
id: adaptor
|
||||
---
|
||||
|
||||
# Adaptor
|
||||
|
||||
Converter for net/http handlers to/from Fiber request handlers, special thanks to [@arsmn](https://github.com/arsmn)!
|
||||
|
||||
## Signatures
|
||||
| Name | Signature | Description
|
||||
| :--- | :--- | :---
|
||||
| HTTPHandler | `HTTPHandler(h http.Handler) fiber.Handler` | http.Handler -> fiber.Handler
|
||||
| HTTPHandlerFunc | `HTTPHandlerFunc(h http.HandlerFunc) fiber.Handler` | http.HandlerFunc -> fiber.Handler
|
||||
| HTTPMiddleware | `HTTPHandlerFunc(mw func(http.Handler) http.Handler) fiber.Handler` | func(http.Handler) http.Handler -> fiber.Handler
|
||||
| FiberHandler | `FiberHandler(h fiber.Handler) http.Handler` | fiber.Handler -> http.Handler
|
||||
| FiberHandlerFunc | `FiberHandlerFunc(h fiber.Handler) http.HandlerFunc` | fiber.Handler -> http.HandlerFunc
|
||||
| FiberApp | `FiberApp(app *fiber.App) http.HandlerFunc` | Fiber app -> http.HandlerFunc
|
||||
| ConvertRequest | `ConvertRequest(c *fiber.Ctx, forServer bool) (*http.Request, error)` | fiber.Ctx -> http.Request
|
||||
| CopyContextToFiberContext | `CopyContextToFiberContext(context interface{}, requestContext *fasthttp.RequestCtx)` | context.Context -> fasthttp.RequestCtx
|
||||
|
||||
## Examples
|
||||
|
||||
### net/http to Fiber
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gofiber/fiber/v2/middleware/adaptor"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// New fiber app
|
||||
app := fiber.New()
|
||||
|
||||
// http.Handler -> fiber.Handler
|
||||
app.Get("/", adaptor.HTTPHandler(handler(greet)))
|
||||
|
||||
// http.HandlerFunc -> fiber.Handler
|
||||
app.Get("/func", adaptor.HTTPHandlerFunc(greet))
|
||||
|
||||
// Listen on port 3000
|
||||
app.Listen(":3000")
|
||||
}
|
||||
|
||||
func handler(f http.HandlerFunc) http.Handler {
|
||||
return http.HandlerFunc(f)
|
||||
}
|
||||
|
||||
func greet(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Fprint(w, "Hello World!")
|
||||
}
|
||||
```
|
||||
|
||||
### net/http middleware to Fiber
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gofiber/fiber/v2/middleware/adaptor"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// New fiber app
|
||||
app := fiber.New()
|
||||
|
||||
// http middleware -> fiber.Handler
|
||||
app.Use(adaptor.HTTPMiddleware(logMiddleware))
|
||||
|
||||
// Listen on port 3000
|
||||
app.Listen(":3000")
|
||||
}
|
||||
|
||||
func logMiddleware(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
log.Println("log middleware")
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
### Fiber Handler to net/http
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gofiber/fiber/v2/middleware/adaptor"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// fiber.Handler -> http.Handler
|
||||
http.Handle("/", adaptor.FiberHandler(greet))
|
||||
|
||||
// fiber.Handler -> http.HandlerFunc
|
||||
http.HandleFunc("/func", adaptor.FiberHandlerFunc(greet))
|
||||
|
||||
// Listen on port 3000
|
||||
http.ListenAndServe(":3000", nil)
|
||||
}
|
||||
|
||||
func greet(c *fiber.Ctx) error {
|
||||
return c.SendString("Hello World!")
|
||||
}
|
||||
```
|
||||
|
||||
### Fiber App to net/http
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gofiber/fiber/v2/middleware/adaptor"
|
||||
)
|
||||
|
||||
func main() {
|
||||
app := fiber.New()
|
||||
|
||||
app.Get("/greet", greet)
|
||||
|
||||
// Listen on port 3000
|
||||
http.ListenAndServe(":3000", adaptor.FiberApp(app))
|
||||
}
|
||||
|
||||
func greet(c *fiber.Ctx) error {
|
||||
return c.SendString("Hello World!")
|
||||
}
|
||||
```
|
||||
|
||||
### Fiber Context to (net/http).Request
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gofiber/fiber/v2/middleware/adaptor"
|
||||
)
|
||||
|
||||
func main() {
|
||||
app := fiber.New()
|
||||
|
||||
app.Get("/greet", greetWithHTTPReq)
|
||||
|
||||
// Listen on port 3000
|
||||
http.ListenAndServe(":3000", adaptor.FiberApp(app))
|
||||
}
|
||||
|
||||
func greetWithHTTPReq(c *fiber.Ctx) error {
|
||||
httpReq, err := adaptor.ConvertRequest(c, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return c.SendString("Request URL: " + httpReq.URL.String())
|
||||
}
|
||||
```
|
85
docs/api/middleware/basicauth.md
Normal file
85
docs/api/middleware/basicauth.md
Normal file
|
@ -0,0 +1,85 @@
|
|||
---
|
||||
id: basicauth
|
||||
---
|
||||
|
||||
# BasicAuth
|
||||
|
||||
Basic Authentication middleware for [Fiber](https://github.com/gofiber/fiber) that provides an HTTP basic authentication. It calls the next handler for valid credentials and [401 Unauthorized](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/401) or a custom response for missing or invalid credentials.
|
||||
|
||||
## Signatures
|
||||
|
||||
```go
|
||||
func New(config Config) fiber.Handler
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
Import the middleware package that is part of the Fiber web framework
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gofiber/fiber/v2/middleware/basicauth"
|
||||
)
|
||||
```
|
||||
|
||||
After you initiate your Fiber app, you can use the following possibilities:
|
||||
|
||||
```go
|
||||
// Provide a minimal config
|
||||
app.Use(basicauth.New(basicauth.Config{
|
||||
Users: map[string]string{
|
||||
"john": "doe",
|
||||
"admin": "123456",
|
||||
},
|
||||
}))
|
||||
|
||||
// Or extend your config for customization
|
||||
app.Use(basicauth.New(basicauth.Config{
|
||||
Users: map[string]string{
|
||||
"john": "doe",
|
||||
"admin": "123456",
|
||||
},
|
||||
Realm: "Forbidden",
|
||||
Authorizer: func(user, pass string) bool {
|
||||
if user == "john" && pass == "doe" {
|
||||
return true
|
||||
}
|
||||
if user == "admin" && pass == "123456" {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
},
|
||||
Unauthorized: func(c *fiber.Ctx) error {
|
||||
return c.SendFile("./unauthorized.html")
|
||||
},
|
||||
ContextUsername: "_user",
|
||||
ContextPassword: "_pass",
|
||||
}))
|
||||
```
|
||||
|
||||
## Config
|
||||
|
||||
| Property | Type | Description | Default |
|
||||
|:----------------|:----------------------------|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------|:----------------------|
|
||||
| Next | `func(*fiber.Ctx) bool` | Next defines a function to skip this middleware when returned true. | `nil` |
|
||||
| Users | `map[string]string` | Users defines the allowed credentials. | `map[string]string{}` |
|
||||
| Realm | `string` | Realm is a string to define the realm attribute of BasicAuth. The realm identifies the system to authenticate against and can be used by clients to save credentials. | `"Restricted"` |
|
||||
| Authorizer | `func(string, string) bool` | Authorizer defines a function to check the credentials. It will be called with a username and password and is expected to return true or false to indicate approval. | `nil` |
|
||||
| Unauthorized | `fiber.Handler` | Unauthorized defines the response body for unauthorized responses. | `nil` |
|
||||
| ContextUsername | `interface{}` | ContextUsername is the key to store the username in Locals. | `"username"` |
|
||||
| ContextPassword | `interface{}` | ContextPassword is the key to store the password in Locals. | `"password"` |
|
||||
|
||||
## Default Config
|
||||
|
||||
```go
|
||||
var ConfigDefault = Config{
|
||||
Next: nil,
|
||||
Users: map[string]string{},
|
||||
Realm: "Restricted",
|
||||
Authorizer: nil,
|
||||
Unauthorized: nil,
|
||||
ContextUsername: "username",
|
||||
ContextPassword: "password",
|
||||
}
|
||||
```
|
99
docs/api/middleware/cache.md
Normal file
99
docs/api/middleware/cache.md
Normal file
|
@ -0,0 +1,99 @@
|
|||
---
|
||||
id: cache
|
||||
---
|
||||
|
||||
# Cache
|
||||
|
||||
Cache middleware for [Fiber](https://github.com/gofiber/fiber) designed to intercept responses and cache them. This middleware will cache the `Body`, `Content-Type` and `StatusCode` using the `c.Path()` as unique identifier. Special thanks to [@codemicro](https://github.com/codemicro/fiber-cache) for creating this middleware for Fiber core!
|
||||
|
||||
Request Directives<br />
|
||||
`Cache-Control: no-cache` will return the up-to-date response but still caches it. You will always get a `miss` cache status.<br />
|
||||
`Cache-Control: no-store` will refrain from caching. You will always get the up-to-date response.
|
||||
|
||||
## Signatures
|
||||
|
||||
```go
|
||||
func New(config ...Config) fiber.Handler
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
Import the middleware package that is part of the Fiber web framework
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gofiber/fiber/v2/middleware/cache"
|
||||
)
|
||||
```
|
||||
|
||||
After you initiate your Fiber app, you can use the following possibilities:
|
||||
|
||||
```go
|
||||
// Initialize default config
|
||||
app.Use(cache.New())
|
||||
|
||||
// Or extend your config for customization
|
||||
app.Use(cache.New(cache.Config{
|
||||
Next: func(c *fiber.Ctx) bool {
|
||||
return c.Query("noCache") == "true"
|
||||
},
|
||||
Expiration: 30 * time.Minute,
|
||||
CacheControl: true,
|
||||
}))
|
||||
```
|
||||
|
||||
Or you can custom key and expire time like this:
|
||||
|
||||
```go
|
||||
app.Use(cache.New(cache.Config{
|
||||
ExpirationGenerator: func(c *fiber.Ctx, cfg *cache.Config) time.Duration {
|
||||
newCacheTime, _ := strconv.Atoi(c.GetRespHeader("Cache-Time", "600"))
|
||||
return time.Second * time.Duration(newCacheTime)
|
||||
},
|
||||
KeyGenerator: func(c *fiber.Ctx) string {
|
||||
return utils.CopyString(c.Path())
|
||||
},
|
||||
}))
|
||||
|
||||
app.Get("/", func(c *fiber.Ctx) error {
|
||||
c.Response().Header.Add("Cache-Time", "6000")
|
||||
return c.SendString("hi")
|
||||
})
|
||||
```
|
||||
|
||||
## Config
|
||||
|
||||
| Property | Type | Description | Default |
|
||||
|:---------------------|:------------------------------------------------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:------------------------------------------------------------------|
|
||||
| Next | `func(*fiber.Ctx) bool` | Next defines a function that is executed before creating the cache entry and can be used to execute the request without cache creation. If an entry already exists, it will be used. If you want to completely bypass the cache functionality in certain cases, you should use the [skip middleware](./skip.md). | `nil` |
|
||||
| Expiration | `time.Duration` | Expiration is the time that a cached response will live. | `1 * time.Minute` |
|
||||
| CacheHeader | `string` | CacheHeader is the header on the response header that indicates the cache status, with the possible return values "hit," "miss," or "unreachable." | `X-Cache` |
|
||||
| CacheControl | `bool` | CacheControl enables client-side caching if set to true. | `false` |
|
||||
| KeyGenerator | `func(*fiber.Ctx) string` | Key allows you to generate custom keys. | `func(c *fiber.Ctx) string { return utils.CopyString(c.Path()) }` |
|
||||
| ExpirationGenerator | `func(*fiber.Ctx, *cache.Config) time.Duration` | ExpirationGenerator allows you to generate custom expiration keys based on the request. | `nil` |
|
||||
| Storage | `fiber.Storage` | Store is used to store the state of the middleware. | In-memory store |
|
||||
| Store (Deprecated) | `fiber.Storage` | Deprecated: Use Storage instead. | In-memory store |
|
||||
| Key (Deprecated) | `func(*fiber.Ctx) string` | Deprecated: Use KeyGenerator instead. | `nil` |
|
||||
| StoreResponseHeaders | `bool` | StoreResponseHeaders allows you to store additional headers generated by next middlewares & handler. | `false` |
|
||||
| MaxBytes | `uint` | MaxBytes is the maximum number of bytes of response bodies simultaneously stored in cache. | `0` (No limit) |
|
||||
| Methods | `[]string` | Methods specifies the HTTP methods to cache. | `[]string{fiber.MethodGet, fiber.MethodHead}` |
|
||||
|
||||
## Default Config
|
||||
|
||||
```go
|
||||
var ConfigDefault = Config{
|
||||
Next: nil,
|
||||
Expiration: 1 * time.Minute,
|
||||
CacheHeader: "X-Cache",
|
||||
CacheControl: false,
|
||||
KeyGenerator: func(c *fiber.Ctx) string {
|
||||
return utils.CopyString(c.Path())
|
||||
},
|
||||
ExpirationGenerator: nil,
|
||||
StoreResponseHeaders: false,
|
||||
Storage: nil,
|
||||
MaxBytes: 0,
|
||||
Methods: []string{fiber.MethodGet, fiber.MethodHead},
|
||||
}
|
||||
```
|
85
docs/api/middleware/compress.md
Normal file
85
docs/api/middleware/compress.md
Normal file
|
@ -0,0 +1,85 @@
|
|||
---
|
||||
id: compress
|
||||
---
|
||||
|
||||
# Compress
|
||||
|
||||
Compression middleware for [Fiber](https://github.com/gofiber/fiber) that will compress the response using `gzip`, `deflate` and `brotli` compression depending on the [Accept-Encoding](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Encoding) header.
|
||||
|
||||
:::note
|
||||
The compression middleware refrains from compressing bodies that are smaller than 200 bytes. This decision is based on the observation that, in such cases, the compressed size is likely to exceed the original size, making compression inefficient. [more](https://github.com/valyala/fasthttp/blob/497922a21ef4b314f393887e9c6147b8c3e3eda4/http.go#L1713-L1715)
|
||||
:::
|
||||
|
||||
## Signatures
|
||||
|
||||
```go
|
||||
func New(config ...Config) fiber.Handler
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
Import the middleware package that is part of the Fiber web framework
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gofiber/fiber/v2/middleware/compress"
|
||||
)
|
||||
```
|
||||
|
||||
After you initiate your Fiber app, you can use the following possibilities:
|
||||
|
||||
```go
|
||||
// Initialize default config
|
||||
app.Use(compress.New())
|
||||
|
||||
// Or extend your config for customization
|
||||
app.Use(compress.New(compress.Config{
|
||||
Level: compress.LevelBestSpeed, // 1
|
||||
}))
|
||||
|
||||
// Skip middleware for specific routes
|
||||
app.Use(compress.New(compress.Config{
|
||||
Next: func(c *fiber.Ctx) bool {
|
||||
return c.Path() == "/dont_compress"
|
||||
},
|
||||
Level: compress.LevelBestSpeed, // 1
|
||||
}))
|
||||
```
|
||||
|
||||
## Config
|
||||
|
||||
### Config
|
||||
|
||||
| Property | Type | Description | Default |
|
||||
|:---------|:------------------------|:--------------------------------------------------------------------|:-------------------|
|
||||
| Next | `func(*fiber.Ctx) bool` | Next defines a function to skip this middleware when returned true. | `nil` |
|
||||
| Level | `Level` | Level determines the compression algorithm. | `LevelDefault (0)` |
|
||||
|
||||
Possible values for the "Level" field are:
|
||||
|
||||
- `LevelDisabled (-1)`: Compression is disabled.
|
||||
- `LevelDefault (0)`: Default compression level.
|
||||
- `LevelBestSpeed (1)`: Best compression speed.
|
||||
- `LevelBestCompression (2)`: Best compression.
|
||||
|
||||
## Default Config
|
||||
|
||||
```go
|
||||
var ConfigDefault = Config{
|
||||
Next: nil,
|
||||
Level: LevelDefault,
|
||||
}
|
||||
```
|
||||
|
||||
## Constants
|
||||
|
||||
```go
|
||||
// Compression levels
|
||||
const (
|
||||
LevelDisabled = -1
|
||||
LevelDefault = 0
|
||||
LevelBestSpeed = 1
|
||||
LevelBestCompression = 2
|
||||
)
|
||||
```
|
214
docs/api/middleware/cors.md
Normal file
214
docs/api/middleware/cors.md
Normal file
|
@ -0,0 +1,214 @@
|
|||
---
|
||||
id: cors
|
||||
---
|
||||
|
||||
# CORS
|
||||
|
||||
CORS (Cross-Origin Resource Sharing) is a middleware for [Fiber](https://github.com/gofiber/fiber) that allows servers to specify who can access its resources and how. It's not a security feature, but a way to relax the security model of web browsers for cross-origin requests. You can learn more about CORS on [Mozilla Developer Network](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS).
|
||||
|
||||
This middleware works by adding CORS headers to responses from your Fiber application. These headers specify which origins, methods, and headers are allowed for cross-origin requests. It also handles preflight requests, which are a CORS mechanism to check if the actual request is safe to send.
|
||||
|
||||
The middleware uses the `AllowOrigins` option to control which origins can make cross-origin requests. It supports single origin, multiple origins, subdomain matching, and wildcard origin. It also allows programmatic origin validation with the `AllowOriginsFunc` option.
|
||||
|
||||
To ensure that the provided `AllowOrigins` origins are correctly formatted, this middleware validates and normalizes them. It checks for valid schemes, i.e., HTTP or HTTPS, and it will automatically remove trailing slashes. If the provided origin is invalid, the middleware will panic.
|
||||
|
||||
When configuring CORS, it's important to avoid [common pitfalls](#common-pitfalls) like using a wildcard origin with credentials, being overly permissive with origins, and inadequate validation with `AllowOriginsFunc`. Misconfiguration can expose your application to various security risks.
|
||||
|
||||
## Signatures
|
||||
|
||||
```go
|
||||
func New(config ...Config) fiber.Handler
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
Import the middleware package that is part of the Fiber web framework
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gofiber/fiber/v2/middleware/cors"
|
||||
)
|
||||
```
|
||||
|
||||
After you initiate your Fiber app, you can use the following possibilities:
|
||||
|
||||
### Basic usage
|
||||
|
||||
To use the default configuration, simply use `cors.New()`. This will allow wildcard origins '*', all methods, no credentials, and no headers or exposed headers.
|
||||
|
||||
```go
|
||||
app.Use(cors.New())
|
||||
```
|
||||
|
||||
### Custom configuration (specific origins, headers, etc.)
|
||||
|
||||
```go
|
||||
// Initialize default config
|
||||
app.Use(cors.New())
|
||||
|
||||
// Or extend your config for customization
|
||||
app.Use(cors.New(cors.Config{
|
||||
AllowOrigins: "https://gofiber.io, https://gofiber.net",
|
||||
AllowHeaders: "Origin, Content-Type, Accept",
|
||||
}))
|
||||
```
|
||||
|
||||
### Dynamic origin validation
|
||||
|
||||
You can use `AllowOriginsFunc` to programmatically determine whether to allow a request based on its origin. This is useful when you need to validate origins against a database or other dynamic sources. The function should return `true` if the origin is allowed, and `false` otherwise.
|
||||
|
||||
Be sure to review the [security considerations](#security-considerations) when using `AllowOriginsFunc`.
|
||||
|
||||
:::caution
|
||||
Never allow `AllowOriginsFunc` to return `true` for all origins. This is particularly crucial when `AllowCredentials` is set to `true`. Doing so can bypass the restriction of using a wildcard origin with credentials, exposing your application to serious security threats.
|
||||
|
||||
If you need to allow wildcard origins, use `AllowOrigins` with a wildcard `"*"` instead of `AllowOriginsFunc`.
|
||||
:::
|
||||
|
||||
```go
|
||||
// dbCheckOrigin checks if the origin is in the list of allowed origins in the database.
|
||||
func dbCheckOrigin(db *sql.DB, origin string) bool {
|
||||
// Placeholder query - adjust according to your database schema and query needs
|
||||
query := "SELECT COUNT(*) FROM allowed_origins WHERE origin = $1"
|
||||
|
||||
var count int
|
||||
err := db.QueryRow(query, origin).Scan(&count)
|
||||
if err != nil {
|
||||
// Handle error (e.g., log it); for simplicity, we return false here
|
||||
return false
|
||||
}
|
||||
|
||||
return count > 0
|
||||
}
|
||||
|
||||
// ...
|
||||
|
||||
app.Use(cors.New(cors.Config{
|
||||
AllowOriginsFunc: func(origin string) bool {
|
||||
return dbCheckOrigin(db, origin)
|
||||
},
|
||||
}))
|
||||
```
|
||||
|
||||
### Prohibited usage
|
||||
|
||||
The following example is prohibited because it can expose your application to security risks. It sets `AllowOrigins` to `"*"` (a wildcard) and `AllowCredentials` to `true`.
|
||||
|
||||
```go
|
||||
app.Use(cors.New(cors.Config{
|
||||
AllowOrigins: "*",
|
||||
AllowCredentials: true,
|
||||
}))
|
||||
```
|
||||
|
||||
This will result in the following panic:
|
||||
|
||||
```
|
||||
panic: [CORS] 'AllowCredentials' is true, but 'AllowOrigins' cannot be set to `"*"`.
|
||||
```
|
||||
|
||||
## Config
|
||||
|
||||
| Property | Type | Description | Default |
|
||||
|:-----------------|:---------------------------|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:-----------------------------------|
|
||||
| Next | `func(*fiber.Ctx) bool` | Next defines a function to skip this middleware when returned true. | `nil` |
|
||||
| AllowOriginsFunc | `func(origin string) bool` | `AllowOriginsFunc` is a function that dynamically determines whether to allow a request based on its origin. If this function returns `true`, the 'Access-Control-Allow-Origin' response header will be set to the request's 'origin' header. This function is only used if the request's origin doesn't match any origin in `AllowOrigins`. | `nil` |
|
||||
| AllowOrigins | `string` | AllowOrigins defines a comma separated list of origins that may access the resource. This supports subdomain matching, so you can use a value like "https://*.example.com" to allow any subdomain of example.com to submit requests. | `"*"` |
|
||||
| AllowMethods | `string` | AllowMethods defines a list of methods allowed when accessing the resource. This is used in response to a preflight request. | `"GET,POST,HEAD,PUT,DELETE,PATCH"` |
|
||||
| AllowHeaders | `string` | AllowHeaders defines a list of request headers that can be used when making the actual request. This is in response to a preflight request. | `""` |
|
||||
| AllowCredentials | `bool` | AllowCredentials indicates whether or not the response to the request can be exposed when the credentials flag is true. When used as part of a response to a preflight request, this indicates whether or not the actual request can be made using credentials. Note: If true, AllowOrigins cannot be set to a wildcard (`"*"`) to prevent security vulnerabilities. | `false` |
|
||||
| ExposeHeaders | `string` | ExposeHeaders defines whitelist headers that clients are allowed to access. | `""` |
|
||||
| MaxAge | `int` | MaxAge indicates how long (in seconds) the results of a preflight request can be cached. If you pass MaxAge 0, the Access-Control-Max-Age header will not be added and the browser will use 5 seconds by default. To disable caching completely, pass MaxAge value negative. It will set the Access-Control-Max-Age header to 0. | `0` |
|
||||
|
||||
## Default Config
|
||||
|
||||
```go
|
||||
var ConfigDefault = Config{
|
||||
Next: nil,
|
||||
AllowOriginsFunc: nil,
|
||||
AllowOrigins: "*",
|
||||
AllowMethods: strings.Join([]string{
|
||||
fiber.MethodGet,
|
||||
fiber.MethodPost,
|
||||
fiber.MethodHead,
|
||||
fiber.MethodPut,
|
||||
fiber.MethodDelete,
|
||||
fiber.MethodPatch,
|
||||
}, ","),
|
||||
AllowHeaders: "",
|
||||
AllowCredentials: false,
|
||||
ExposeHeaders: "",
|
||||
MaxAge: 0,
|
||||
}
|
||||
```
|
||||
|
||||
## Subdomain Matching
|
||||
|
||||
The `AllowOrigins` configuration supports matching subdomains at any level. This means you can use a value like `"https://*.example.com"` to allow any subdomain of `example.com` to submit requests, including multiple subdomain levels such as `"https://sub.sub.example.com"`.
|
||||
|
||||
### Example
|
||||
|
||||
If you want to allow CORS requests from any subdomain of `example.com`, including nested subdomains, you can configure the `AllowOrigins` like so:
|
||||
|
||||
```go
|
||||
app.Use(cors.New(cors.Config{
|
||||
AllowOrigins: "https://*.example.com",
|
||||
}))
|
||||
```
|
||||
|
||||
# How It Works
|
||||
|
||||
The CORS middleware works by adding the necessary CORS headers to responses from your Fiber application. These headers tell browsers what origins, methods, and headers are allowed for cross-origin requests.
|
||||
|
||||
When a request comes in, the middleware first checks if it's a preflight request, which is a CORS mechanism to determine whether the actual request is safe to send. Preflight requests are HTTP OPTIONS requests with specific CORS headers. If it's a preflight request, the middleware responds with the appropriate CORS headers and ends the request.
|
||||
|
||||
If it's not a preflight request, the middleware adds the CORS headers to the response and passes the request to the next handler. The actual CORS headers added depend on the configuration of the middleware.
|
||||
|
||||
The `AllowOrigins` option controls which origins can make cross-origin requests. The middleware handles different `AllowOrigins` configurations as follows:
|
||||
|
||||
- **Single origin:** If `AllowOrigins` is set to a single origin like `"http://www.example.com"`, and that origin matches the origin of the incoming request, the middleware adds the header `Access-Control-Allow-Origin: http://www.example.com` to the response.
|
||||
|
||||
- **Multiple origins:** If `AllowOrigins` is set to multiple origins like `"https://example.com, https://www.example.com"`, the middleware picks the origin that matches the origin of the incoming request.
|
||||
|
||||
- **Subdomain matching:** If `AllowOrigins` includes `"https://*.example.com"`, a subdomain like `https://sub.example.com` will be matched and `"https://sub.example.com"` will be the header. This will also match `https://sub.sub.example.com` and so on, but not `https://example.com`.
|
||||
|
||||
- **Wildcard origin:** If `AllowOrigins` is set to `"*"`, the middleware uses that and adds the header `Access-Control-Allow-Origin: *` to the response.
|
||||
|
||||
In all cases above, except the **Wildcard origin**, the middleware will either add the `Access-Control-Allow-Origin` header to the response matching the origin of the incoming request, or it will not add the header at all if the origin is not allowed.
|
||||
|
||||
- **Programmatic origin validation:**: The middleware also handles the `AllowOriginsFunc` option, which allows you to programmatically determine if an origin is allowed. If `AllowOriginsFunc` returns `true` for an origin, the middleware sets the `Access-Control-Allow-Origin` header to that origin.
|
||||
|
||||
The `AllowMethods` option controls which HTTP methods are allowed. For example, if `AllowMethods` is set to `"GET, POST"`, the middleware adds the header `Access-Control-Allow-Methods: GET, POST` to the response.
|
||||
|
||||
The `AllowHeaders` option specifies which headers are allowed in the actual request. The middleware sets the Access-Control-Allow-Headers response header to the value of `AllowHeaders`. This informs the client which headers it can use in the actual request.
|
||||
|
||||
The `AllowCredentials` option indicates whether the response to the request can be exposed when the credentials flag is true. If `AllowCredentials` is set to `true`, the middleware adds the header `Access-Control-Allow-Credentials: true` to the response. To prevent security vulnerabilities, `AllowCredentials` cannot be set to `true` if `AllowOrigins` is set to a wildcard (`*`).
|
||||
|
||||
The `ExposeHeaders` option defines a whitelist of headers that clients are allowed to access. If `ExposeHeaders` is set to `"X-Custom-Header"`, the middleware adds the header `Access-Control-Expose-Headers: X-Custom-Header` to the response.
|
||||
|
||||
The `MaxAge` option indicates how long the results of a preflight request can be cached. If `MaxAge` is set to `3600`, the middleware adds the header `Access-Control-Max-Age: 3600` to the response.
|
||||
|
||||
The `Vary` header is used in this middleware to inform the client that the server's response to a request. For or both preflight and actual requests, the Vary header is set to `Access-Control-Request-Method` and `Access-Control-Request-Headers`. For preflight requests, the Vary header is also set to `Origin`. The `Vary` header is important for caching. It helps caches (like a web browser's cache or a CDN) determine when a cached response can be used in response to a future request, and when the server needs to be queried for a new response.
|
||||
|
||||
## Security Considerations
|
||||
|
||||
When configuring CORS, misconfiguration can potentially expose your application to various security risks. Here are some secure configurations and common pitfalls to avoid:
|
||||
|
||||
### Secure Configurations
|
||||
|
||||
- **Specify Allowed Origins**: Instead of using a wildcard (`"*"`), specify the exact domains allowed to make requests. For example, `AllowOrigins: "https://www.example.com, https://api.example.com"` ensures only these domains can make cross-origin requests to your application.
|
||||
|
||||
- **Use Credentials Carefully**: If your application needs to support credentials in cross-origin requests, ensure `AllowCredentials` is set to `true` and specify exact origins in `AllowOrigins`. Do not use a wildcard origin in this case.
|
||||
|
||||
- **Limit Exposed Headers**: Only whitelist headers that are necessary for the client-side application by setting `ExposeHeaders` appropriately. This minimizes the risk of exposing sensitive information.
|
||||
|
||||
### Common Pitfalls
|
||||
|
||||
- **Wildcard Origin with Credentials**: Setting `AllowOrigins` to `"*"` (a wildcard) and `AllowCredentials` to `true` is a common misconfiguration. This combination is prohibited because it can expose your application to security risks.
|
||||
|
||||
- **Overly Permissive Origins**: Specifying too many origins or using overly broad patterns (e.g., `https://*.example.com`) can inadvertently allow malicious sites to interact with your application. Be as specific as possible with allowed origins.
|
||||
|
||||
- **Inadequate `AllowOriginsFunc` Validation**: When using `AllowOriginsFunc` for dynamic origin validation, ensure the function includes robust checks to prevent unauthorized origins from being accepted. Overly permissive validation can lead to security vulnerabilities. Never allow `AllowOriginsFunc` to return `true` for all origins. This is particularly crucial when `AllowCredentials` is set to `true`. Doing so can bypass the restriction of using a wildcard origin with credentials, exposing your application to serious security threats. If you need to allow wildcard origins, use `AllowOrigins` with a wildcard `"*"` instead of `AllowOriginsFunc`.
|
||||
|
||||
Remember, the key to secure CORS configuration is specificity and caution. By carefully selecting which origins, methods, and headers are allowed, you can help protect your application from cross-origin attacks.
|
256
docs/api/middleware/csrf.md
Normal file
256
docs/api/middleware/csrf.md
Normal file
|
@ -0,0 +1,256 @@
|
|||
---
|
||||
id: csrf
|
||||
---
|
||||
|
||||
# CSRF
|
||||
|
||||
The CSRF middleware for [Fiber](https://github.com/gofiber/fiber) provides protection against [Cross-Site Request Forgery](https://en.wikipedia.org/wiki/Cross-site_request_forgery) (CSRF) attacks. Requests made using methods other than those defined as 'safe' by [RFC9110#section-9.2.1](https://datatracker.ietf.org/doc/html/rfc9110.html#section-9.2.1) (GET, HEAD, OPTIONS, and TRACE) are validated using tokens. If a potential attack is detected, the middleware will return a default 403 Forbidden error.
|
||||
|
||||
This middleware offers two [Token Validation Patterns](#token-validation-patterns): the [Double Submit Cookie Pattern (default)](#double-submit-cookie-pattern-default), and the [Synchronizer Token Pattern (with Session)](#synchronizer-token-pattern-with-session).
|
||||
|
||||
As a [Defense In Depth](#defense-in-depth) measure, this middleware performs [Referer Checking](#referer-checking) for HTTPS requests.
|
||||
|
||||
## Token Generation
|
||||
|
||||
CSRF tokens are generated on 'safe' requests and when the existing token has expired or hasn't been set yet. If `SingleUseToken` is `true`, a new token is generated after each use. Retrieve the CSRF token using `c.Locals(contextKey)`, where `contextKey` is defined within the configuration.
|
||||
|
||||
## Security Considerations
|
||||
|
||||
This middleware is designed to protect against CSRF attacks but does not protect against other attack vectors, such as XSS. It should be used in combination with other security measures.
|
||||
|
||||
:::danger
|
||||
Never use 'safe' methods to mutate data, for example, never use a GET request to modify a resource. This middleware will not protect against CSRF attacks on 'safe' methods.
|
||||
:::
|
||||
|
||||
### Token Validation Patterns
|
||||
|
||||
#### Double Submit Cookie Pattern (Default)
|
||||
|
||||
By default, the middleware generates and stores tokens using the `fiber.Storage` interface. These tokens are not linked to any particular user session, and they are validated using the Double Submit Cookie pattern. The token is stored in a cookie, and then sent as a header on requests. The middleware compares the cookie value with the header value to validate the token. This is a secure pattern that does not require a user session.
|
||||
|
||||
When the authorization status changes, the previously issued token MUST be deleted, and a new one generated. See [Token Lifecycle](#token-lifecycle) [Deleting Tokens](#deleting-tokens) for more information.
|
||||
|
||||
:::caution
|
||||
When using this pattern, it's important to set the `CookieSameSite` option to `Lax` or `Strict` and ensure that the Extractor is not `CsrfFromCookie`, and KeyLookup is not `cookie:<name>`.
|
||||
:::
|
||||
|
||||
:::note
|
||||
When using this pattern, this middleware uses our [Storage](https://github.com/gofiber/storage) package to support various databases through a single interface. The default configuration for Storage saves data to memory. See [Custom Storage/Database](#custom-storagedatabase) for customizing the storage.
|
||||
:::
|
||||
|
||||
#### Synchronizer Token Pattern (with Session)
|
||||
|
||||
When using this middleware with a user session, the middleware can be configured to store the token within the session. This method is recommended when using a user session, as it is generally more secure than the Double Submit Cookie Pattern.
|
||||
|
||||
When using this pattern it's important to regenerate the session when the authorization status changes, this will also delete the token. See: [Token Lifecycle](#token-lifecycle) for more information.
|
||||
|
||||
:::caution
|
||||
Pre-sessions are required and will be created automatically if not present. Use a session value to indicate authentication instead of relying on presence of a session.
|
||||
:::
|
||||
|
||||
### Defense In Depth
|
||||
|
||||
When using this middleware, it's recommended to serve your pages over HTTPS, set the `CookieSecure` option to `true`, and set the `CookieSameSite` option to `Lax` or `Strict`. This ensures that the cookie is only sent over HTTPS and not on requests from external sites.
|
||||
|
||||
:::note
|
||||
Cookie prefixes `__Host-` and `__Secure-` can be used to further secure the cookie. Note that these prefixes are not supported by all browsers and there are other limitations. See [MDN#Set-Cookie#cookie_prefixes](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#cookie_prefixes) for more information.
|
||||
|
||||
To use these prefixes, set the `CookieName` option to `__Host-csrf_` or `__Secure-csrf_`.
|
||||
:::
|
||||
|
||||
### Referer Checking
|
||||
|
||||
For HTTPS requests, this middleware performs strict referer checking. Even if a subdomain can set or modify cookies on your domain, it can't force a user to post to your application since that request won't come from your own exact domain.
|
||||
|
||||
:::caution
|
||||
When HTTPS requests are protected by CSRF, referer checking is always carried out.
|
||||
|
||||
The Referer header is automatically included in requests by all modern browsers, including those made using the JS Fetch API. However, if you're making use of this middleware with a custom client, it's important to ensure that the client sends a valid Referer header.
|
||||
:::
|
||||
|
||||
|
||||
### Token Lifecycle
|
||||
|
||||
Tokens are valid until they expire or until they are deleted. By default, tokens are valid for 1 hour, and each subsequent request extends the expiration by 1 hour. The token only expires if the user doesn't make a request for the duration of the expiration time.
|
||||
|
||||
#### Token Reuse
|
||||
|
||||
By default, tokens may be used multiple times. If you want to delete the token after it has been used, you can set the `SingleUseToken` option to `true`. This will delete the token after it has been used, and a new token will be generated on the next request.
|
||||
|
||||
:::info
|
||||
Using `SingleUseToken` comes with usability trade-offs and is not enabled by default. For example, it can interfere with the user experience if the user has multiple tabs open or uses the back button.
|
||||
:::
|
||||
|
||||
#### Deleting Tokens
|
||||
|
||||
When the authorization status changes, the CSRF token MUST be deleted, and a new one generated. This can be done by calling `handler.DeleteToken(c)`.
|
||||
|
||||
```go
|
||||
if handler, ok := app.AcquireCtx(ctx).Locals(csrf.ConfigDefault.HandlerContextKey).(*CSRFHandler); ok {
|
||||
if err := handler.DeleteToken(app.AcquireCtx(ctx)); err != nil {
|
||||
// handle error
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
:::tip
|
||||
If you are using this middleware with the fiber session middleware, then you can simply call `session.Destroy()`, `session.Regenerate()`, or `session.Reset()` to delete session and the token stored therein.
|
||||
:::
|
||||
|
||||
### BREACH
|
||||
|
||||
It's important to note that the token is sent as a header on every request. If you include the token in a page that is vulnerable to [BREACH](https://en.wikipedia.org/wiki/BREACH), an attacker may be able to extract the token. To mitigate this, ensure your pages are served over HTTPS, disable HTTP compression, and implement rate limiting for requests.
|
||||
|
||||
## Signatures
|
||||
|
||||
```go
|
||||
func New(config ...Config) fiber.Handler
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
Import the middleware package that is part of the Fiber web framework:
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gofiber/fiber/v2/middleware/csrf"
|
||||
)
|
||||
```
|
||||
|
||||
After initializing your Fiber app, you can use the following code to initialize the middleware:
|
||||
|
||||
```go
|
||||
// Initialize default config
|
||||
app.Use(csrf.New())
|
||||
|
||||
// Or extend your config for customization
|
||||
app.Use(csrf.New(csrf.Config{
|
||||
KeyLookup: "header:X-Csrf-Token",
|
||||
CookieName: "csrf_",
|
||||
CookieSameSite: "Lax",
|
||||
Expiration: 1 * time.Hour,
|
||||
KeyGenerator: utils.UUIDv4,
|
||||
}))
|
||||
```
|
||||
|
||||
## Config
|
||||
|
||||
| Property | Type | Description | Default |
|
||||
|:------------------|:-----------------------------------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:-----------------------------|
|
||||
| Next | `func(*fiber.Ctx) bool` | Next defines a function to skip this middleware when returned true. | `nil` |
|
||||
| KeyLookup | `string` | KeyLookup is a string in the form of "`<source>:<key>`" that is used to create an Extractor that extracts the token from the request. Possible values: "`header:<name>`", "`query:<name>`", "`param:<name>`", "`form:<name>`", "`cookie:<name>`". Ignored if an Extractor is explicitly set. | "header:X-Csrf-Token" |
|
||||
| CookieName | `string` | Name of the csrf cookie. This cookie will store the csrf key. | "csrf_" |
|
||||
| CookieDomain | `string` | Domain of the CSRF cookie. | "" |
|
||||
| CookiePath | `string` | Path of the CSRF cookie. | "" |
|
||||
| CookieSecure | `bool` | Indicates if the CSRF cookie is secure. | false |
|
||||
| CookieHTTPOnly | `bool` | Indicates if the CSRF cookie is HTTP-only. | false |
|
||||
| CookieSameSite | `string` | Value of SameSite cookie. | "Lax" |
|
||||
| CookieSessionOnly | `bool` | Decides whether the cookie should last for only the browser session. Ignores Expiration if set to true. | false |
|
||||
| Expiration | `time.Duration` | Expiration is the duration before the CSRF token will expire. | 1 * time.Hour |
|
||||
| SingleUseToken | `bool` | SingleUseToken indicates if the CSRF token be destroyed and a new one generated on each use. (See TokenLifecycle) | false |
|
||||
| Storage | `fiber.Storage` | Store is used to store the state of the middleware. | `nil` |
|
||||
| Session | `*session.Store` | Session is used to store the state of the middleware. Overrides Storage if set. | `nil` |
|
||||
| SessionKey | `string` | SessionKey is the key used to store the token within the session. | "fiber.csrf.token" |
|
||||
| ContextKey | `inteface{}` | Context key to store the generated CSRF token into the context. If left empty, the token will not be stored within the context. | "" |
|
||||
| KeyGenerator | `func() string` | KeyGenerator creates a new CSRF token. | utils.UUID |
|
||||
| CookieExpires | `time.Duration` (Deprecated) | Deprecated: Please use Expiration. | 0 |
|
||||
| Cookie | `*fiber.Cookie` (Deprecated) | Deprecated: Please use Cookie* related fields. | `nil` |
|
||||
| TokenLookup | `string` (Deprecated) | Deprecated: Please use KeyLookup. | "" |
|
||||
| ErrorHandler | `fiber.ErrorHandler` | ErrorHandler is executed when an error is returned from fiber.Handler. | DefaultErrorHandler |
|
||||
| Extractor | `func(*fiber.Ctx) (string, error)` | Extractor returns the CSRF token. If set, this will be used in place of an Extractor based on KeyLookup. | Extractor based on KeyLookup |
|
||||
| HandlerContextKey | `interface{}` | HandlerContextKey is used to store the CSRF Handler into context. | "fiber.csrf.handler" |
|
||||
|
||||
### Default Config
|
||||
|
||||
```go
|
||||
var ConfigDefault = Config{
|
||||
KeyLookup: "header:" + HeaderName,
|
||||
CookieName: "csrf_",
|
||||
CookieSameSite: "Lax",
|
||||
Expiration: 1 * time.Hour,
|
||||
KeyGenerator: utils.UUIDv4,
|
||||
ErrorHandler: defaultErrorHandler,
|
||||
Extractor: CsrfFromHeader(HeaderName),
|
||||
SessionKey: "fiber.csrf.token",
|
||||
HandlerContextKey: "fiber.csrf.handler",
|
||||
}
|
||||
```
|
||||
|
||||
### Recommended Config (with session)
|
||||
|
||||
It's recommended to use this middleware with [fiber/middleware/session](https://docs.gofiber.io/api/middleware/session) to store the CSRF token within the session. This is generally more secure than the default configuration.
|
||||
|
||||
```go
|
||||
var ConfigDefault = Config{
|
||||
KeyLookup: "header:" + HeaderName,
|
||||
CookieName: "__Host-csrf_",
|
||||
CookieSameSite: "Lax",
|
||||
CookieSecure: true,
|
||||
CookieSessionOnly: true,
|
||||
CookieHTTPOnly: true,
|
||||
Expiration: 1 * time.Hour,
|
||||
KeyGenerator: utils.UUIDv4,
|
||||
ErrorHandler: defaultErrorHandler,
|
||||
Extractor: CsrfFromHeader(HeaderName),
|
||||
Session: session.Store,
|
||||
SessionKey: "fiber.csrf.token",
|
||||
HandlerContextKey: "fiber.csrf.handler",
|
||||
}
|
||||
```
|
||||
|
||||
## Constants
|
||||
|
||||
```go
|
||||
const (
|
||||
HeaderName = "X-Csrf-Token"
|
||||
)
|
||||
```
|
||||
|
||||
## Sentinel Errors
|
||||
|
||||
The CSRF middleware utilizes a set of sentinel errors to handle various scenarios and communicate errors effectively. These can be used within a [custom error handler](#custom-error-handler) to handle errors returned by the middleware.
|
||||
|
||||
### Errors Returned to Error Handler
|
||||
|
||||
- `ErrTokenNotFound`: Indicates that the CSRF token was not found.
|
||||
- `ErrTokenInvalid`: Indicates that the CSRF token is invalid.
|
||||
- `ErrNoReferer`: Indicates that the referer was not supplied.
|
||||
- `ErrBadReferer`: Indicates that the referer is invalid.
|
||||
|
||||
If you use the default error handler, the client will receive a 403 Forbidden error without any additional information.
|
||||
|
||||
## Custom Error Handler
|
||||
|
||||
You can use a custom error handler to handle errors returned by the CSRF middleware. The error handler is executed when an error is returned from the middleware. The error handler is passed the error returned from the middleware and the fiber.Ctx.
|
||||
|
||||
Example, returning a JSON response for API requests and rendering an error page for other requests:
|
||||
|
||||
```go
|
||||
app.Use(csrf.New(csrf.Config{
|
||||
ErrorHandler: func(c *fiber.Ctx, err error) error {
|
||||
accepts := c.Accepts("html", "json")
|
||||
path := c.Path()
|
||||
if accepts == "json" || strings.HasPrefix(path, "/api/") {
|
||||
return c.Status(fiber.StatusForbidden).JSON(fiber.Map{
|
||||
"error": "Forbidden",
|
||||
})
|
||||
}
|
||||
return c.Status(fiber.StatusForbidden).Render("error", fiber.Map{
|
||||
"Title": "Forbidden",
|
||||
"Status": fiber.StatusForbidden,
|
||||
}, "layouts/main")
|
||||
},
|
||||
}))
|
||||
```
|
||||
|
||||
## Custom Storage/Database
|
||||
|
||||
You can use any storage from our [storage](https://github.com/gofiber/storage/) package.
|
||||
|
||||
```go
|
||||
storage := sqlite3.New() // From github.com/gofiber/storage/sqlite3
|
||||
app.Use(csrf.New(csrf.Config{
|
||||
Storage: storage,
|
||||
}))
|
||||
```
|
82
docs/api/middleware/earlydata.md
Normal file
82
docs/api/middleware/earlydata.md
Normal file
|
@ -0,0 +1,82 @@
|
|||
---
|
||||
id: earlydata
|
||||
---
|
||||
|
||||
# EarlyData
|
||||
|
||||
The Early Data middleware for [Fiber](https://github.com/gofiber/fiber) adds support for TLS 1.3's early data ("0-RTT") feature.
|
||||
Citing [RFC 8446](https://datatracker.ietf.org/doc/html/rfc8446#section-2-3), when a client and server share a PSK, TLS 1.3 allows clients to send data on the first flight ("early data") to speed up the request, effectively reducing the regular 1-RTT request to a 0-RTT request.
|
||||
|
||||
Make sure to enable fiber's `EnableTrustedProxyCheck` config option before using this middleware in order to not trust bogus HTTP request headers of the client.
|
||||
|
||||
Also be aware that enabling support for early data in your reverse proxy (e.g. nginx, as done with a simple `ssl_early_data on;`) makes requests replayable. Refer to the following documents before continuing:
|
||||
|
||||
- https://datatracker.ietf.org/doc/html/rfc8446#section-8
|
||||
- https://blog.trailofbits.com/2019/03/25/what-application-developers-need-to-know-about-tls-early-data-0rtt/
|
||||
|
||||
By default, this middleware allows early data requests on safe HTTP request methods only and rejects the request otherwise, i.e. aborts the request before executing your handler. This behavior can be controlled by the `AllowEarlyData` config option.
|
||||
Safe HTTP methods — `GET`, `HEAD`, `OPTIONS` and `TRACE` — should not modify a state on the server.
|
||||
|
||||
## Signatures
|
||||
|
||||
```go
|
||||
func New(config ...Config) fiber.Handler
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
Import the middleware package that is part of the Fiber web framework
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gofiber/fiber/v2/middleware/earlydata"
|
||||
)
|
||||
```
|
||||
|
||||
After you initiate your Fiber app, you can use the following possibilities:
|
||||
|
||||
```go
|
||||
// Initialize default config
|
||||
app.Use(earlydata.New())
|
||||
|
||||
// Or extend your config for customization
|
||||
app.Use(earlydata.New(earlydata.Config{
|
||||
Error: fiber.ErrTooEarly,
|
||||
// ...
|
||||
}))
|
||||
```
|
||||
|
||||
## Config
|
||||
|
||||
| Property | Type | Description | Default |
|
||||
|:---------------|:------------------------|:-------------------------------------------------------------------------------------|:-------------------------------------------------------|
|
||||
| Next | `func(*fiber.Ctx) bool` | Next defines a function to skip this middleware when returned true. | `nil` |
|
||||
| IsEarlyData | `func(*fiber.Ctx) bool` | IsEarlyData returns whether the request is an early-data request. | Function checking if "Early-Data" header equals "1" |
|
||||
| AllowEarlyData | `func(*fiber.Ctx) bool` | AllowEarlyData returns whether the early-data request should be allowed or rejected. | Function rejecting on unsafe and allowing safe methods |
|
||||
| Error | `error` | Error is returned in case an early-data request is rejected. | `fiber.ErrTooEarly` |
|
||||
|
||||
## Default Config
|
||||
|
||||
```go
|
||||
var ConfigDefault = Config{
|
||||
IsEarlyData: func(c *fiber.Ctx) bool {
|
||||
return c.Get(DefaultHeaderName) == DefaultHeaderTrueValue
|
||||
},
|
||||
|
||||
AllowEarlyData: func(c *fiber.Ctx) bool {
|
||||
return fiber.IsMethodSafe(c.Method())
|
||||
},
|
||||
|
||||
Error: fiber.ErrTooEarly,
|
||||
}
|
||||
```
|
||||
|
||||
## Constants
|
||||
|
||||
```go
|
||||
const (
|
||||
DefaultHeaderName = "Early-Data"
|
||||
DefaultHeaderTrueValue = "1"
|
||||
)
|
||||
```
|
101
docs/api/middleware/encryptcookie.md
Normal file
101
docs/api/middleware/encryptcookie.md
Normal file
|
@ -0,0 +1,101 @@
|
|||
---
|
||||
id: encryptcookie
|
||||
---
|
||||
|
||||
# Encrypt Cookie
|
||||
|
||||
Encrypt Cookie is a middleware for [Fiber](https://github.com/gofiber/fiber) that secures your cookie values through encryption.
|
||||
|
||||
:::note
|
||||
This middleware encrypts cookie values and not the cookie names.
|
||||
:::
|
||||
|
||||
## Signatures
|
||||
|
||||
```go
|
||||
// Intitializes the middleware
|
||||
func New(config ...Config) fiber.Handler
|
||||
|
||||
// Returns a random 32 character long string
|
||||
func GenerateKey() string
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
To use the Encrypt Cookie middleware, first, import the middleware package as part of the Fiber web framework:
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gofiber/fiber/v2/middleware/encryptcookie"
|
||||
)
|
||||
```
|
||||
|
||||
Once you've imported the middleware package, you can use it inside your Fiber app:
|
||||
|
||||
```go
|
||||
// Provide a minimal configuration
|
||||
app.Use(encryptcookie.New(encryptcookie.Config{
|
||||
Key: "secret-thirty-2-character-string",
|
||||
}))
|
||||
|
||||
// Retrieve the encrypted cookie value
|
||||
app.Get("/", func(c *fiber.Ctx) error {
|
||||
return c.SendString("value=" + c.Cookies("test"))
|
||||
})
|
||||
|
||||
// Create an encrypted cookie
|
||||
app.Post("/", func(c *fiber.Ctx) error {
|
||||
c.Cookie(&fiber.Cookie{
|
||||
Name: "test",
|
||||
Value: "SomeThing",
|
||||
})
|
||||
return nil
|
||||
})
|
||||
```
|
||||
|
||||
:::note
|
||||
`Key` must be a 32 character string. It's used to encrypt the values, so make sure it is random and keep it secret.
|
||||
You can run `openssl rand -base64 32` or call `encryptcookie.GenerateKey()` to create a random key for you.
|
||||
Make sure not to set `Key` to `encryptcookie.GenerateKey()` because that will create a new key every run.
|
||||
:::
|
||||
|
||||
## Config
|
||||
|
||||
| Property | Type | Description | Default |
|
||||
|:----------|:----------------------------------------------------|:------------------------------------------------------------------------------------------------------|:-----------------------------|
|
||||
| Next | `func(*fiber.Ctx) bool` | A function to skip this middleware when returned true. | `nil` |
|
||||
| Except | `[]string` | Array of cookie keys that should not be encrypted. | `[]` |
|
||||
| Key | `string` | A base64-encoded unique key to encode & decode cookies. Required. Key length should be 32 characters. | (No default, required field) |
|
||||
| Encryptor | `func(decryptedString, key string) (string, error)` | A custom function to encrypt cookies. | `EncryptCookie` |
|
||||
| Decryptor | `func(encryptedString, key string) (string, error)` | A custom function to decrypt cookies. | `DecryptCookie` |
|
||||
|
||||
## Default Config
|
||||
|
||||
```go
|
||||
var ConfigDefault = Config{
|
||||
Next: nil,
|
||||
Except: []string{},
|
||||
Key: "",
|
||||
Encryptor: EncryptCookie,
|
||||
Decryptor: DecryptCookie,
|
||||
}
|
||||
```
|
||||
|
||||
## Usage With Other Middlewares That Reads Or Modify Cookies
|
||||
Place the encryptcookie middleware before any other middleware that reads or modifies cookies. For example, if you are using the CSRF middleware, ensure that the encryptcookie middleware is placed before it. Failure to do so may prevent the CSRF middleware from reading the encrypted cookie.
|
||||
|
||||
You may also choose to exclude certain cookies from encryption. For instance, if you are using the CSRF middleware with a frontend framework like Angular, and the framework reads the token from a cookie, you should exclude that cookie from encryption. This can be achieved by adding the cookie name to the Except array in the configuration:
|
||||
|
||||
```go
|
||||
app.Use(encryptcookie.New(encryptcookie.Config{
|
||||
Key: "secret-thirty-2-character-string",
|
||||
Except: []string{csrf.ConfigDefault.CookieName}, // exclude CSRF cookie
|
||||
}))
|
||||
app.Use(csrf.New(csrf.Config{
|
||||
KeyLookup: "header:" + csrf.HeaderName,
|
||||
CookieSameSite: "Lax",
|
||||
CookieSecure: true,
|
||||
CookieHTTPOnly: false,
|
||||
}))
|
||||
```
|
69
docs/api/middleware/envvar.md
Normal file
69
docs/api/middleware/envvar.md
Normal file
|
@ -0,0 +1,69 @@
|
|||
---
|
||||
id: envvar
|
||||
---
|
||||
|
||||
# EnvVar
|
||||
|
||||
EnvVar middleware for [Fiber](https://github.com/gofiber/fiber) that can be used to expose environment variables with various options.
|
||||
|
||||
## Signatures
|
||||
|
||||
```go
|
||||
func New(config ...Config) fiber.Handler
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
Import the middleware package that is part of the Fiber web framework
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gofiber/fiber/v2/middleware/envvar"
|
||||
)
|
||||
```
|
||||
|
||||
After you initiate your Fiber app, you can use the following possibilities:
|
||||
|
||||
```go
|
||||
// Initialize default config
|
||||
app.Use("/expose/envvars", envvar.New())
|
||||
|
||||
// Or extend your config for customization
|
||||
app.Use("/expose/envvars", envvar.New(
|
||||
envvar.Config{
|
||||
ExportVars: map[string]string{"testKey": "", "testDefaultKey": "testDefaultVal"},
|
||||
ExcludeVars: map[string]string{"excludeKey": ""},
|
||||
}),
|
||||
)
|
||||
```
|
||||
|
||||
:::note
|
||||
You will need to provide a path to use the envvar middleware.
|
||||
:::
|
||||
|
||||
## Response
|
||||
|
||||
Http response contract:
|
||||
```
|
||||
{
|
||||
"vars": {
|
||||
"someEnvVariable": "someValue",
|
||||
"anotherEnvVariable": "anotherValue",
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Config
|
||||
|
||||
| Property | Type | Description | Default |
|
||||
|:------------|:--------------------|:-----------------------------------------------------------------------------|:--------|
|
||||
| ExportVars | `map[string]string` | ExportVars specifies the environment variables that should be exported. | `nil` |
|
||||
| ExcludeVars | `map[string]string` | ExcludeVars specifies the environment variables that should not be exported. | `nil` |
|
||||
|
||||
## Default Config
|
||||
|
||||
```go
|
||||
Config{}
|
||||
```
|
62
docs/api/middleware/etag.md
Normal file
62
docs/api/middleware/etag.md
Normal file
|
@ -0,0 +1,62 @@
|
|||
---
|
||||
id: etag
|
||||
---
|
||||
|
||||
# ETag
|
||||
|
||||
ETag middleware for [Fiber](https://github.com/gofiber/fiber) that lets caches be more efficient and save bandwidth, as a web server does not need to resend a full response if the content has not changed.
|
||||
|
||||
## Signatures
|
||||
|
||||
```go
|
||||
func New(config ...Config) fiber.Handler
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
Import the middleware package that is part of the Fiber web framework
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gofiber/fiber/v2/middleware/etag"
|
||||
)
|
||||
```
|
||||
|
||||
After you initiate your Fiber app, you can use the following possibilities:
|
||||
|
||||
```go
|
||||
// Initialize default config
|
||||
app.Use(etag.New())
|
||||
|
||||
// Get / receives Etag: "13-1831710635" in response header
|
||||
app.Get("/", func(c *fiber.Ctx) error {
|
||||
return c.SendString("Hello, World!")
|
||||
})
|
||||
|
||||
// Or extend your config for customization
|
||||
app.Use(etag.New(etag.Config{
|
||||
Weak: true,
|
||||
}))
|
||||
|
||||
// Get / receives Etag: "W/"13-1831710635" in response header
|
||||
app.Get("/", func(c *fiber.Ctx) error {
|
||||
return c.SendString("Hello, World!")
|
||||
})
|
||||
```
|
||||
|
||||
## Config
|
||||
|
||||
| Property | Type | Description | Default |
|
||||
|:---------|:------------------------|:-------------------------------------------------------------------------------------------------------------------|:--------|
|
||||
| Weak | `bool` | Weak indicates that a weak validator is used. Weak etags are easy to generate but are less useful for comparisons. | `false` |
|
||||
| Next | `func(*fiber.Ctx) bool` | Next defines a function to skip this middleware when returned true. | `nil` |
|
||||
|
||||
## Default Config
|
||||
|
||||
```go
|
||||
var ConfigDefault = Config{
|
||||
Next: nil,
|
||||
Weak: false,
|
||||
}
|
||||
```
|
72
docs/api/middleware/expvar.md
Normal file
72
docs/api/middleware/expvar.md
Normal file
|
@ -0,0 +1,72 @@
|
|||
---
|
||||
id: expvar
|
||||
---
|
||||
|
||||
# ExpVar
|
||||
|
||||
Expvar middleware for [Fiber](https://github.com/gofiber/fiber) that serves via its HTTP server runtime exposed variants in the JSON format. The package is typically only imported for the side effect of registering its HTTP handlers. The handled path is `/debug/vars`.
|
||||
|
||||
## Signatures
|
||||
|
||||
```go
|
||||
func New() fiber.Handler
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
Import the middleware package that is part of the Fiber web framework
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/gofiber/fiber/v2"
|
||||
expvarmw "github.com/gofiber/fiber/v2/middleware/expvar"
|
||||
)
|
||||
```
|
||||
|
||||
After you initiate your Fiber app, you can use the following possibilities:
|
||||
```go
|
||||
var count = expvar.NewInt("count")
|
||||
|
||||
app.Use(expvarmw.New())
|
||||
app.Get("/", func(c *fiber.Ctx) error {
|
||||
count.Add(1)
|
||||
|
||||
return c.SendString(fmt.Sprintf("hello expvar count %d", count.Value()))
|
||||
})
|
||||
```
|
||||
|
||||
Visit path `/debug/vars` to see all vars and use query `r=key` to filter exposed variables.
|
||||
|
||||
```bash
|
||||
curl 127.0.0.1:3000
|
||||
hello expvar count 1
|
||||
|
||||
curl 127.0.0.1:3000/debug/vars
|
||||
{
|
||||
"cmdline": ["xxx"],
|
||||
"count": 1,
|
||||
"expvarHandlerCalls": 33,
|
||||
"expvarRegexpErrors": 0,
|
||||
"memstats": {...}
|
||||
}
|
||||
|
||||
curl 127.0.0.1:3000/debug/vars?r=c
|
||||
{
|
||||
"cmdline": ["xxx"],
|
||||
"count": 1
|
||||
}
|
||||
```
|
||||
|
||||
## Config
|
||||
|
||||
| Property | Type | Description | Default |
|
||||
|:---------|:------------------------|:--------------------------------------------------------------------|:--------|
|
||||
| Next | `func(*fiber.Ctx) bool` | Next defines a function to skip this middleware when returned true. | `nil` |
|
||||
|
||||
## Default Config
|
||||
|
||||
```go
|
||||
var ConfigDefault = Config{
|
||||
Next: nil,
|
||||
}
|
||||
```
|
63
docs/api/middleware/favicon.md
Normal file
63
docs/api/middleware/favicon.md
Normal file
|
@ -0,0 +1,63 @@
|
|||
---
|
||||
id: favicon
|
||||
---
|
||||
|
||||
# Favicon
|
||||
|
||||
Favicon middleware for [Fiber](https://github.com/gofiber/fiber) that ignores favicon requests or caches a provided icon in memory to improve performance by skipping disk access. User agents request favicon.ico frequently and indiscriminately, so you may wish to exclude these requests from your logs by using this middleware before your logger middleware.
|
||||
|
||||
:::note
|
||||
This middleware is exclusively for serving the default, implicit favicon, which is GET /favicon.ico or [custom favicon URL](#config).
|
||||
:::
|
||||
|
||||
## Signatures
|
||||
|
||||
```go
|
||||
func New(config ...Config) fiber.Handler
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
Import the middleware package that is part of the Fiber web framework
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gofiber/fiber/v2/middleware/favicon"
|
||||
)
|
||||
```
|
||||
|
||||
After you initiate your Fiber app, you can use the following possibilities:
|
||||
|
||||
```go
|
||||
// Initialize default config
|
||||
app.Use(favicon.New())
|
||||
|
||||
// Or extend your config for customization
|
||||
app.Use(favicon.New(favicon.Config{
|
||||
File: "./favicon.ico",
|
||||
URL: "/favicon.ico",
|
||||
}))
|
||||
```
|
||||
|
||||
## Config
|
||||
|
||||
| Property | Type | Description | Default |
|
||||
|:-------------|:------------------------|:---------------------------------------------------------------------------------|:---------------------------|
|
||||
| Next | `func(*fiber.Ctx) bool` | Next defines a function to skip this middleware when returned true. | `nil` |
|
||||
| Data | `[]byte` | Raw data of the favicon file. This can be used instead of `File`. | `nil` |
|
||||
| File | `string` | File holds the path to an actual favicon that will be cached. | "" |
|
||||
| URL | `string` | URL for favicon handler. | "/favicon.ico" |
|
||||
| FileSystem | `http.FileSystem` | FileSystem is an optional alternate filesystem to search for the favicon in. | `nil` |
|
||||
| CacheControl | `string` | CacheControl defines how the Cache-Control header in the response should be set. | "public, max-age=31536000" |
|
||||
|
||||
## Default Config
|
||||
|
||||
```go
|
||||
var ConfigDefault = Config{
|
||||
Next: nil,
|
||||
File: "",
|
||||
URL: fPath,
|
||||
CacheControl: "public, max-age=31536000",
|
||||
}
|
||||
```
|
300
docs/api/middleware/filesystem.md
Normal file
300
docs/api/middleware/filesystem.md
Normal file
|
@ -0,0 +1,300 @@
|
|||
---
|
||||
id: filesystem
|
||||
---
|
||||
|
||||
# FileSystem
|
||||
|
||||
Filesystem middleware for [Fiber](https://github.com/gofiber/fiber) that enables you to serve files from a directory.
|
||||
|
||||
:::caution
|
||||
**`:params` & `:optionals?` within the prefix path are not supported!**
|
||||
|
||||
**To handle paths with spaces (or other url encoded values) make sure to set `fiber.Config{ UnescapePath: true }`**
|
||||
:::
|
||||
|
||||
## Signatures
|
||||
|
||||
```go
|
||||
func New(config Config) fiber.Handler
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
Import the middleware package that is part of the Fiber web framework
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gofiber/fiber/v2/middleware/filesystem"
|
||||
)
|
||||
```
|
||||
|
||||
After you initiate your Fiber app, you can use the following possibilities:
|
||||
|
||||
```go
|
||||
// Provide a minimal config
|
||||
app.Use(filesystem.New(filesystem.Config{
|
||||
Root: http.Dir("./assets"),
|
||||
}))
|
||||
|
||||
// Or extend your config for customization
|
||||
app.Use(filesystem.New(filesystem.Config{
|
||||
Root: http.Dir("./assets"),
|
||||
Browse: true,
|
||||
Index: "index.html",
|
||||
NotFoundFile: "404.html",
|
||||
MaxAge: 3600,
|
||||
}))
|
||||
```
|
||||
|
||||
|
||||
> If your environment (Go 1.16+) supports it, we recommend using Go Embed instead of the other solutions listed as this one is native to Go and the easiest to use.
|
||||
|
||||
## embed
|
||||
|
||||
[Embed](https://golang.org/pkg/embed/) is the native method to embed files in a Golang excecutable. Introduced in Go 1.16.
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"io/fs"
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gofiber/fiber/v2/middleware/filesystem"
|
||||
)
|
||||
|
||||
// Embed a single file
|
||||
//go:embed index.html
|
||||
var f embed.FS
|
||||
|
||||
// Embed a directory
|
||||
//go:embed static/*
|
||||
var embedDirStatic embed.FS
|
||||
|
||||
func main() {
|
||||
app := fiber.New()
|
||||
|
||||
app.Use("/", filesystem.New(filesystem.Config{
|
||||
Root: http.FS(f),
|
||||
}))
|
||||
|
||||
// Access file "image.png" under `static/` directory via URL: `http://<server>/static/image.png`.
|
||||
// Without `PathPrefix`, you have to access it via URL:
|
||||
// `http://<server>/static/static/image.png`.
|
||||
app.Use("/static", filesystem.New(filesystem.Config{
|
||||
Root: http.FS(embedDirStatic),
|
||||
PathPrefix: "static",
|
||||
Browse: true,
|
||||
}))
|
||||
|
||||
log.Fatal(app.Listen(":3000"))
|
||||
}
|
||||
```
|
||||
|
||||
## pkger
|
||||
|
||||
[https://github.com/markbates/pkger](https://github.com/markbates/pkger)
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gofiber/fiber/v2/middleware/filesystem"
|
||||
|
||||
"github.com/markbates/pkger"
|
||||
)
|
||||
|
||||
func main() {
|
||||
app := fiber.New()
|
||||
|
||||
app.Use("/assets", filesystem.New(filesystem.Config{
|
||||
Root: pkger.Dir("/assets"),
|
||||
}))
|
||||
|
||||
log.Fatal(app.Listen(":3000"))
|
||||
}
|
||||
```
|
||||
|
||||
## packr
|
||||
|
||||
[https://github.com/gobuffalo/packr](https://github.com/gobuffalo/packr)
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gofiber/fiber/v2/middleware/filesystem"
|
||||
|
||||
"github.com/gobuffalo/packr/v2"
|
||||
)
|
||||
|
||||
func main() {
|
||||
app := fiber.New()
|
||||
|
||||
app.Use("/assets", filesystem.New(filesystem.Config{
|
||||
Root: packr.New("Assets Box", "/assets"),
|
||||
}))
|
||||
|
||||
log.Fatal(app.Listen(":3000"))
|
||||
}
|
||||
```
|
||||
|
||||
## go.rice
|
||||
|
||||
[https://github.com/GeertJohan/go.rice](https://github.com/GeertJohan/go.rice)
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gofiber/fiber/v2/middleware/filesystem"
|
||||
|
||||
"github.com/GeertJohan/go.rice"
|
||||
)
|
||||
|
||||
func main() {
|
||||
app := fiber.New()
|
||||
|
||||
app.Use("/assets", filesystem.New(filesystem.Config{
|
||||
Root: rice.MustFindBox("assets").HTTPBox(),
|
||||
}))
|
||||
|
||||
log.Fatal(app.Listen(":3000"))
|
||||
}
|
||||
```
|
||||
|
||||
## fileb0x
|
||||
|
||||
[https://github.com/UnnoTed/fileb0x](https://github.com/UnnoTed/fileb0x)
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gofiber/fiber/v2/middleware/filesystem"
|
||||
|
||||
"<Your go module>/myEmbeddedFiles"
|
||||
)
|
||||
|
||||
func main() {
|
||||
app := fiber.New()
|
||||
|
||||
app.Use("/assets", filesystem.New(filesystem.Config{
|
||||
Root: myEmbeddedFiles.HTTP,
|
||||
}))
|
||||
|
||||
log.Fatal(app.Listen(":3000"))
|
||||
}
|
||||
```
|
||||
|
||||
## statik
|
||||
|
||||
[https://github.com/rakyll/statik](https://github.com/rakyll/statik)
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gofiber/fiber/v2/middleware/filesystem"
|
||||
|
||||
// Use blank to invoke init function and register data to statik
|
||||
_ "<Your go module>/statik"
|
||||
"github.com/rakyll/statik/fs"
|
||||
)
|
||||
|
||||
func main() {
|
||||
statikFS, err := fs.New()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
app := fiber.New()
|
||||
|
||||
app.Use("/", filesystem.New(filesystem.Config{
|
||||
Root: statikFS,
|
||||
}))
|
||||
|
||||
log.Fatal(app.Listen(":3000"))
|
||||
}
|
||||
```
|
||||
|
||||
## Config
|
||||
|
||||
| Property | Type | Description | Default |
|
||||
|:-------------------|:------------------------|:------------------------------------------------------------------------------------------------------------|:-------------|
|
||||
| Next | `func(*fiber.Ctx) bool` | Next defines a function to skip this middleware when returned true. | `nil` |
|
||||
| Root | `http.FileSystem` | Root is a FileSystem that provides access to a collection of files and directories. | `nil` |
|
||||
| PathPrefix | `string` | PathPrefix defines a prefix to be added to a filepath when reading a file from the FileSystem. | "" |
|
||||
| Browse | `bool` | Enable directory browsing. | `false` |
|
||||
| Index | `string` | Index file for serving a directory. | "index.html" |
|
||||
| MaxAge | `int` | The value for the Cache-Control HTTP-header that is set on the file response. MaxAge is defined in seconds. | 0 |
|
||||
| NotFoundFile | `string` | File to return if the path is not found. Useful for SPA's. | "" |
|
||||
| ContentTypeCharset | `string` | The value for the Content-Type HTTP-header that is set on the file response. | "" |
|
||||
|
||||
## Default Config
|
||||
|
||||
```go
|
||||
var ConfigDefault = Config{
|
||||
Next: nil,
|
||||
Root: nil,
|
||||
PathPrefix: "",
|
||||
Browse: false,
|
||||
Index: "/index.html",
|
||||
MaxAge: 0,
|
||||
ContentTypeCharset: "",
|
||||
}
|
||||
```
|
||||
|
||||
## Utils
|
||||
|
||||
### SendFile
|
||||
|
||||
Serves a file from an [HTTP file system](https://pkg.go.dev/net/http#FileSystem) at the specified path.
|
||||
|
||||
```go title="Signature" title="Signature"
|
||||
func SendFile(c *fiber.Ctx, filesystem http.FileSystem, path string) error
|
||||
```
|
||||
Import the middleware package that is part of the Fiber web framework
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gofiber/fiber/v2/middleware/filesystem"
|
||||
)
|
||||
```
|
||||
|
||||
```go title="Example"
|
||||
// Define a route to serve a specific file
|
||||
app.Get("/download", func(c *fiber.Ctx) error {
|
||||
// Serve the file using SendFile function
|
||||
err := filesystem.SendFile(c, http.Dir("your/filesystem/root"), "path/to/your/file.txt")
|
||||
if err != nil {
|
||||
// Handle the error, e.g., return a 404 Not Found response
|
||||
return c.Status(fiber.StatusNotFound).SendString("File not found")
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
```
|
||||
|
||||
```go title="Example"
|
||||
// Serve static files from the "build" directory using Fiber's built-in middleware.
|
||||
app.Use("/", filesystem.New(filesystem.Config{
|
||||
Root: http.FS(f), // Specify the root directory for static files.
|
||||
PathPrefix: "build", // Define the path prefix where static files are served.
|
||||
}))
|
||||
|
||||
// For all other routes (wildcard "*"), serve the "index.html" file from the "build" directory.
|
||||
app.Use("*", func(ctx *fiber.Ctx) error {
|
||||
return filesystem.SendFile(ctx, http.FS(f), "build/index.html")
|
||||
})
|
||||
```
|
106
docs/api/middleware/healthcheck.md
Normal file
106
docs/api/middleware/healthcheck.md
Normal file
|
@ -0,0 +1,106 @@
|
|||
---
|
||||
id: healthcheck
|
||||
---
|
||||
|
||||
# Health Check
|
||||
|
||||
Liveness and readiness probes middleware for [Fiber](https://github.com/gofiber/fiber) that provides two endpoints for checking the liveness and readiness state of HTTP applications.
|
||||
|
||||
## Overview
|
||||
|
||||
- **Liveness Probe**: Checks if the server is up and running.
|
||||
- **Default Endpoint**: `/livez`
|
||||
- **Behavior**: By default returns `true` immediately when the server is operational.
|
||||
|
||||
- **Readiness Probe**: Assesses if the application is ready to handle requests.
|
||||
- **Default Endpoint**: `/readyz`
|
||||
- **Behavior**: By default returns `true` immediately when the server is operational.
|
||||
|
||||
- **HTTP Status Codes**:
|
||||
- `200 OK`: Returned when the checker function evaluates to `true`.
|
||||
- `503 Service Unavailable`: Returned when the checker function evaluates to `false`.
|
||||
|
||||
## Signatures
|
||||
|
||||
```go
|
||||
func New(config Config) fiber.Handler
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
Import the middleware package that is part of the [Fiber](https://github.com/gofiber/fiber) web framework
|
||||
```go
|
||||
import (
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gofiber/fiber/v2/middleware/healthcheck"
|
||||
)
|
||||
```
|
||||
|
||||
After you initiate your [Fiber](https://github.com/gofiber/fiber) app, you can use the following possibilities:
|
||||
|
||||
```go
|
||||
// Provide a minimal config
|
||||
app.Use(healthcheck.New())
|
||||
|
||||
// Or extend your config for customization
|
||||
app.Use(healthcheck.New(healthcheck.Config{
|
||||
LivenessProbe: func(c *fiber.Ctx) bool {
|
||||
return true
|
||||
},
|
||||
LivenessEndpoint: "/live",
|
||||
ReadinessProbe: func(c *fiber.Ctx) bool {
|
||||
return serviceA.Ready() && serviceB.Ready() && ...
|
||||
},
|
||||
ReadinessEndpoint: "/ready",
|
||||
}))
|
||||
```
|
||||
|
||||
## Config
|
||||
|
||||
```go
|
||||
type Config struct {
|
||||
// Next defines a function to skip this middleware when returned true.
|
||||
//
|
||||
// Optional. Default: nil
|
||||
Next func(c *fiber.Ctx) bool
|
||||
|
||||
// Function used for checking the liveness of the application. Returns true if the application
|
||||
// is running and false if it is not. The liveness probe is typically used to indicate if
|
||||
// the application is in a state where it can handle requests (e.g., the server is up and running).
|
||||
//
|
||||
// Optional. Default: func(c *fiber.Ctx) bool { return true }
|
||||
LivenessProbe HealthChecker
|
||||
|
||||
// HTTP endpoint at which the liveness probe will be available.
|
||||
//
|
||||
// Optional. Default: "/livez"
|
||||
LivenessEndpoint string
|
||||
|
||||
// Function used for checking the readiness of the application. Returns true if the application
|
||||
// is ready to process requests and false otherwise. The readiness probe typically checks if all necessary
|
||||
// services, databases, and other dependencies are available for the application to function correctly.
|
||||
//
|
||||
// Optional. Default: func(c *fiber.Ctx) bool { return true }
|
||||
ReadinessProbe HealthChecker
|
||||
|
||||
// HTTP endpoint at which the readiness probe will be available.
|
||||
// Optional. Default: "/readyz"
|
||||
ReadinessEndpoint string
|
||||
}
|
||||
```
|
||||
|
||||
## Default Config
|
||||
|
||||
The default configuration used by this middleware is defined as follows:
|
||||
```go
|
||||
func defaultLivenessProbe(*fiber.Ctx) bool { return true }
|
||||
|
||||
func defaultReadinessProbe(*fiber.Ctx) bool { return true }
|
||||
|
||||
var ConfigDefault = Config{
|
||||
LivenessProbe: defaultLivenessProbe,
|
||||
ReadinessProbe: defaultReadinessProbe,
|
||||
LivenessEndpoint: "/livez",
|
||||
ReadinessEndpoint: "/readyz",
|
||||
}
|
||||
```
|
82
docs/api/middleware/helmet.md
Normal file
82
docs/api/middleware/helmet.md
Normal file
|
@ -0,0 +1,82 @@
|
|||
---
|
||||
id: helmet
|
||||
---
|
||||
|
||||
# Helmet
|
||||
|
||||
Helmet middleware helps secure your apps by setting various HTTP headers.
|
||||
|
||||
## Signatures
|
||||
|
||||
```go
|
||||
func New(config ...Config) fiber.Handler
|
||||
```
|
||||
|
||||
## Examples
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gofiber/fiber/v2/middleware/helmet"
|
||||
)
|
||||
|
||||
func main() {
|
||||
app := fiber.New()
|
||||
|
||||
app.Use(helmet.New())
|
||||
|
||||
app.Get("/", func(c *fiber.Ctx) error {
|
||||
return c.SendString("Welcome!")
|
||||
})
|
||||
|
||||
app.Listen(":3000")
|
||||
}
|
||||
```
|
||||
|
||||
**Test:**
|
||||
|
||||
```curl
|
||||
curl -I http://localhost:3000
|
||||
```
|
||||
|
||||
## Config
|
||||
|
||||
| Property | Type | Description | Default |
|
||||
|:--------------------------|:------------------------|:--------------------------------------------|:-----------------|
|
||||
| Next | `func(*fiber.Ctx) bool` | Next defines a function to skip middleware. | `nil` |
|
||||
| XSSProtection | `string` | XSSProtection | "0" |
|
||||
| ContentTypeNosniff | `string` | ContentTypeNosniff | "nosniff" |
|
||||
| XFrameOptions | `string` | XFrameOptions | "SAMEORIGIN" |
|
||||
| HSTSMaxAge | `int` | HSTSMaxAge | 0 |
|
||||
| HSTSExcludeSubdomains | `bool` | HSTSExcludeSubdomains | false |
|
||||
| ContentSecurityPolicy | `string` | ContentSecurityPolicy | "" |
|
||||
| CSPReportOnly | `bool` | CSPReportOnly | false |
|
||||
| HSTSPreloadEnabled | `bool` | HSTSPreloadEnabled | false |
|
||||
| ReferrerPolicy | `string` | ReferrerPolicy | "ReferrerPolicy" |
|
||||
| PermissionPolicy | `string` | Permissions-Policy | "" |
|
||||
| CrossOriginEmbedderPolicy | `string` | Cross-Origin-Embedder-Policy | "require-corp" |
|
||||
| CrossOriginOpenerPolicy | `string` | Cross-Origin-Opener-Policy | "same-origin" |
|
||||
| CrossOriginResourcePolicy | `string` | Cross-Origin-Resource-Policy | "same-origin" |
|
||||
| OriginAgentCluster | `string` | Origin-Agent-Cluster | "?1" |
|
||||
| XDNSPrefetchControl | `string` | X-DNS-Prefetch-Control | "off" |
|
||||
| XDownloadOptions | `string` | X-Download-Options | "noopen" |
|
||||
| XPermittedCrossDomain | `string` | X-Permitted-Cross-Domain-Policies | "none" |
|
||||
|
||||
## Default Config
|
||||
|
||||
```go
|
||||
var ConfigDefault = Config{
|
||||
XSSProtection: "0",
|
||||
ContentTypeNosniff: "nosniff",
|
||||
XFrameOptions: "SAMEORIGIN",
|
||||
ReferrerPolicy: "no-referrer",
|
||||
CrossOriginEmbedderPolicy: "require-corp",
|
||||
CrossOriginOpenerPolicy: "same-origin",
|
||||
CrossOriginResourcePolicy: "same-origin",
|
||||
OriginAgentCluster: "?1",
|
||||
XDNSPrefetchControl: "off",
|
||||
XDownloadOptions: "noopen",
|
||||
XPermittedCrossDomain: "none",
|
||||
}
|
||||
```
|
83
docs/api/middleware/idempotency.md
Normal file
83
docs/api/middleware/idempotency.md
Normal file
|
@ -0,0 +1,83 @@
|
|||
---
|
||||
id: idempotency
|
||||
---
|
||||
|
||||
# Idempotency
|
||||
|
||||
Idempotency middleware for [Fiber](https://github.com/gofiber/fiber) allows for fault-tolerant APIs where duplicate requests — for example due to networking issues on the client-side — do not erroneously cause the same action performed multiple times on the server-side.
|
||||
|
||||
Refer to https://datatracker.ietf.org/doc/html/draft-ietf-httpapi-idempotency-key-header-02 for a better understanding.
|
||||
|
||||
## Signatures
|
||||
|
||||
```go
|
||||
func New(config ...Config) fiber.Handler
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
Import the middleware package that is part of the Fiber web framework
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gofiber/fiber/v2/middleware/idempotency"
|
||||
)
|
||||
```
|
||||
|
||||
After you initiate your Fiber app, you can use the following possibilities:
|
||||
|
||||
### Default Config
|
||||
|
||||
```go
|
||||
app.Use(idempotency.New())
|
||||
```
|
||||
|
||||
### Custom Config
|
||||
|
||||
```go
|
||||
app.Use(idempotency.New(idempotency.Config{
|
||||
Lifetime: 42 * time.Minute,
|
||||
// ...
|
||||
}))
|
||||
```
|
||||
|
||||
### Config
|
||||
|
||||
| Property | Type | Description | Default |
|
||||
|:--------------------|:------------------------|:-----------------------------------------------------------------------------------------|:-------------------------------|
|
||||
| Next | `func(*fiber.Ctx) bool` | Next defines a function to skip this middleware when returned true. | A function for safe methods |
|
||||
| Lifetime | `time.Duration` | Lifetime is the maximum lifetime of an idempotency key. | 30 * time.Minute |
|
||||
| KeyHeader | `string` | KeyHeader is the name of the header that contains the idempotency key. | "X-Idempotency-Key" |
|
||||
| KeyHeaderValidate | `func(string) error` | KeyHeaderValidate defines a function to validate the syntax of the idempotency header. | A function for UUID validation |
|
||||
| KeepResponseHeaders | `[]string` | KeepResponseHeaders is a list of headers that should be kept from the original response. | nil (keep all headers) |
|
||||
| Lock | `Locker` | Lock locks an idempotency key. | An in-memory locker |
|
||||
| Storage | `fiber.Storage` | Storage stores response data by idempotency key. | An in-memory storage |
|
||||
|
||||
## Default Config
|
||||
|
||||
```go
|
||||
var ConfigDefault = Config{
|
||||
Next: func(c *fiber.Ctx) bool {
|
||||
// Skip middleware if the request was done using a safe HTTP method
|
||||
return fiber.IsMethodSafe(c.Method())
|
||||
},
|
||||
|
||||
Lifetime: 30 * time.Minute,
|
||||
|
||||
KeyHeader: "X-Idempotency-Key",
|
||||
KeyHeaderValidate: func(k string) error {
|
||||
if l, wl := len(k), 36; l != wl { // UUID length is 36 chars
|
||||
return fmt.Errorf("%w: invalid length: %d != %d", ErrInvalidIdempotencyKey, l, wl)
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
|
||||
KeepResponseHeaders: nil,
|
||||
|
||||
Lock: nil, // Set in configDefault so we don't allocate data here.
|
||||
|
||||
Storage: nil, // Set in configDefault so we don't allocate data here.
|
||||
}
|
||||
```
|
243
docs/api/middleware/keyauth.md
Normal file
243
docs/api/middleware/keyauth.md
Normal file
|
@ -0,0 +1,243 @@
|
|||
---
|
||||
id: keyauth
|
||||
---
|
||||
|
||||
# Keyauth
|
||||
|
||||
Key auth middleware provides a key based authentication.
|
||||
|
||||
## Signatures
|
||||
|
||||
```go
|
||||
func New(config ...Config) fiber.Handler
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"crypto/subtle"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gofiber/fiber/v2/middleware/keyauth"
|
||||
)
|
||||
|
||||
var (
|
||||
apiKey = "correct horse battery staple"
|
||||
)
|
||||
|
||||
func validateAPIKey(c *fiber.Ctx, key string) (bool, error) {
|
||||
hashedAPIKey := sha256.Sum256([]byte(apiKey))
|
||||
hashedKey := sha256.Sum256([]byte(key))
|
||||
|
||||
if subtle.ConstantTimeCompare(hashedAPIKey[:], hashedKey[:]) == 1 {
|
||||
return true, nil
|
||||
}
|
||||
return false, keyauth.ErrMissingOrMalformedAPIKey
|
||||
}
|
||||
|
||||
func main() {
|
||||
app := fiber.New()
|
||||
|
||||
// note that the keyauth middleware needs to be defined before the routes are defined!
|
||||
app.Use(keyauth.New(keyauth.Config{
|
||||
KeyLookup: "cookie:access_token",
|
||||
Validator: validateAPIKey,
|
||||
}))
|
||||
|
||||
app.Get("/", func(c *fiber.Ctx) error {
|
||||
return c.SendString("Successfully authenticated!")
|
||||
})
|
||||
|
||||
app.Listen(":3000")
|
||||
}
|
||||
```
|
||||
|
||||
**Test:**
|
||||
|
||||
```bash
|
||||
# No api-key specified -> 400 missing
|
||||
curl http://localhost:3000
|
||||
#> missing or malformed API Key
|
||||
|
||||
curl --cookie "access_token=correct horse battery staple" http://localhost:3000
|
||||
#> Successfully authenticated!
|
||||
|
||||
curl --cookie "access_token=Clearly A Wrong Key" http://localhost:3000
|
||||
#> missing or malformed API Key
|
||||
```
|
||||
|
||||
For a more detailed example, see also the [`github.com/gofiber/recipes`](https://github.com/gofiber/recipes) repository and specifically the `fiber-envoy-extauthz` repository and the [`keyauth example`](https://github.com/gofiber/recipes/blob/master/fiber-envoy-extauthz/authz/main.go) code.
|
||||
|
||||
|
||||
### Authenticate only certain endpoints
|
||||
|
||||
If you want to authenticate only certain endpoints, you can use the `Config` of keyauth and apply a filter function (eg. `authFilter`) like so
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"crypto/subtle"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gofiber/fiber/v2/middleware/keyauth"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
apiKey = "correct horse battery staple"
|
||||
protectedURLs = []*regexp.Regexp{
|
||||
regexp.MustCompile("^/authenticated$"),
|
||||
regexp.MustCompile("^/auth2$"),
|
||||
}
|
||||
)
|
||||
|
||||
func validateAPIKey(c *fiber.Ctx, key string) (bool, error) {
|
||||
hashedAPIKey := sha256.Sum256([]byte(apiKey))
|
||||
hashedKey := sha256.Sum256([]byte(key))
|
||||
|
||||
if subtle.ConstantTimeCompare(hashedAPIKey[:], hashedKey[:]) == 1 {
|
||||
return true, nil
|
||||
}
|
||||
return false, keyauth.ErrMissingOrMalformedAPIKey
|
||||
}
|
||||
|
||||
func authFilter(c *fiber.Ctx) bool {
|
||||
originalURL := strings.ToLower(c.OriginalURL())
|
||||
|
||||
for _, pattern := range protectedURLs {
|
||||
if pattern.MatchString(originalURL) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func main() {
|
||||
app := fiber.New()
|
||||
|
||||
app.Use(keyauth.New(keyauth.Config{
|
||||
Next: authFilter,
|
||||
KeyLookup: "cookie:access_token",
|
||||
Validator: validateAPIKey,
|
||||
}))
|
||||
|
||||
app.Get("/", func(c *fiber.Ctx) error {
|
||||
return c.SendString("Welcome")
|
||||
})
|
||||
app.Get("/authenticated", func(c *fiber.Ctx) error {
|
||||
return c.SendString("Successfully authenticated!")
|
||||
})
|
||||
app.Get("/auth2", func(c *fiber.Ctx) error {
|
||||
return c.SendString("Successfully authenticated 2!")
|
||||
})
|
||||
|
||||
app.Listen(":3000")
|
||||
}
|
||||
```
|
||||
|
||||
Which results in this
|
||||
|
||||
```bash
|
||||
# / does not need to be authenticated
|
||||
curl http://localhost:3000
|
||||
#> Welcome
|
||||
|
||||
# /authenticated needs to be authenticated
|
||||
curl --cookie "access_token=correct horse battery staple" http://localhost:3000/authenticated
|
||||
#> Successfully authenticated!
|
||||
|
||||
# /auth2 needs to be authenticated too
|
||||
curl --cookie "access_token=correct horse battery staple" http://localhost:3000/auth2
|
||||
#> Successfully authenticated 2!
|
||||
```
|
||||
|
||||
### Specifying middleware in the handler
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"crypto/subtle"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gofiber/fiber/v2/middleware/keyauth"
|
||||
)
|
||||
|
||||
const (
|
||||
apiKey = "my-super-secret-key"
|
||||
)
|
||||
|
||||
func main() {
|
||||
app := fiber.New()
|
||||
|
||||
authMiddleware := keyauth.New(keyauth.Config{
|
||||
Validator: func(c *fiber.Ctx, key string) (bool, error) {
|
||||
hashedAPIKey := sha256.Sum256([]byte(apiKey))
|
||||
hashedKey := sha256.Sum256([]byte(key))
|
||||
|
||||
if subtle.ConstantTimeCompare(hashedAPIKey[:], hashedKey[:]) == 1 {
|
||||
return true, nil
|
||||
}
|
||||
return false, keyauth.ErrMissingOrMalformedAPIKey
|
||||
},
|
||||
})
|
||||
|
||||
app.Get("/", func(c *fiber.Ctx) error {
|
||||
return c.SendString("Welcome")
|
||||
})
|
||||
|
||||
app.Get("/allowed", authMiddleware, func(c *fiber.Ctx) error {
|
||||
return c.SendString("Successfully authenticated!")
|
||||
})
|
||||
|
||||
app.Listen(":3000")
|
||||
}
|
||||
```
|
||||
|
||||
Which results in this
|
||||
|
||||
```bash
|
||||
# / does not need to be authenticated
|
||||
curl http://localhost:3000
|
||||
#> Welcome
|
||||
|
||||
# /allowed needs to be authenticated too
|
||||
curl --header "Authorization: Bearer my-super-secret-key" http://localhost:3000/allowed
|
||||
#> Successfully authenticated!
|
||||
```
|
||||
|
||||
## Config
|
||||
|
||||
| Property | Type | Description | Default |
|
||||
|:---------------|:-----------------------------------------|:-----------------------------------------------------------------------------------------------------|:------------------------------|
|
||||
| Next | `func(*fiber.Ctx) bool` | Next defines a function to skip this middleware when returned true. | `nil` |
|
||||
| SuccessHandler | `fiber.Handler` | SuccessHandler defines a function which is executed for a valid key. | `nil` |
|
||||
| ErrorHandler | `fiber.ErrorHandler` | ErrorHandler defines a function which is executed for an invalid key. | `401 Invalid or expired key` |
|
||||
| KeyLookup | `string` | KeyLookup is a string in the form of "`<source>:<name>`" that is used to extract key from the request. | "header:Authorization" |
|
||||
| AuthScheme | `string` | AuthScheme to be used in the Authorization header. | "Bearer" |
|
||||
| Validator | `func(*fiber.Ctx, string) (bool, error)` | Validator is a function to validate the key. | A function for key validation |
|
||||
| ContextKey | `interface{}` | Context key to store the bearer token from the token into context. | "token" |
|
||||
|
||||
## Default Config
|
||||
|
||||
```go
|
||||
var ConfigDefault = Config{
|
||||
SuccessHandler: func(c *fiber.Ctx) error {
|
||||
return c.Next()
|
||||
},
|
||||
ErrorHandler: func(c *fiber.Ctx, err error) error {
|
||||
if err == ErrMissingOrMalformedAPIKey {
|
||||
return c.Status(fiber.StatusUnauthorized).SendString(err.Error())
|
||||
}
|
||||
return c.Status(fiber.StatusUnauthorized).SendString("Invalid or expired API Key")
|
||||
},
|
||||
KeyLookup: "header:" + fiber.HeaderAuthorization,
|
||||
AuthScheme: "Bearer",
|
||||
ContextKey: "token",
|
||||
}
|
||||
```
|
125
docs/api/middleware/limiter.md
Normal file
125
docs/api/middleware/limiter.md
Normal file
|
@ -0,0 +1,125 @@
|
|||
---
|
||||
id: limiter
|
||||
---
|
||||
|
||||
# Limiter
|
||||
|
||||
Limiter middleware for [Fiber](https://github.com/gofiber/fiber) that is used to limit repeat requests to public APIs and/or endpoints such as password reset. It is also useful for API clients, web crawling, or other tasks that need to be throttled.
|
||||
|
||||
:::note
|
||||
This middleware uses our [Storage](https://github.com/gofiber/storage) package to support various databases through a single interface. The default configuration for this middleware saves data to memory, see the examples below for other databases.
|
||||
:::
|
||||
|
||||
:::note
|
||||
This module does not share state with other processes/servers by default.
|
||||
:::
|
||||
|
||||
## Signatures
|
||||
|
||||
```go
|
||||
func New(config ...Config) fiber.Handler
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
Import the middleware package that is part of the Fiber web framework
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gofiber/fiber/v2/middleware/limiter"
|
||||
)
|
||||
```
|
||||
|
||||
After you initiate your Fiber app, you can use the following possibilities:
|
||||
|
||||
```go
|
||||
// Initialize default config
|
||||
app.Use(limiter.New())
|
||||
|
||||
// Or extend your config for customization
|
||||
app.Use(limiter.New(limiter.Config{
|
||||
Next: func(c *fiber.Ctx) bool {
|
||||
return c.IP() == "127.0.0.1"
|
||||
},
|
||||
Max: 20,
|
||||
Expiration: 30 * time.Second,
|
||||
KeyGenerator: func(c *fiber.Ctx) string {
|
||||
return c.Get("x-forwarded-for")
|
||||
},
|
||||
LimitReached: func(c *fiber.Ctx) error {
|
||||
return c.SendFile("./toofast.html")
|
||||
},
|
||||
Storage: myCustomStorage{},
|
||||
}))
|
||||
```
|
||||
|
||||
## Sliding window
|
||||
|
||||
Instead of using the standard fixed window algorithm, you can enable the [sliding window](https://en.wikipedia.org/wiki/Sliding_window_protocol) algorithm.
|
||||
|
||||
A example of such configuration is:
|
||||
|
||||
```go
|
||||
app.Use(limiter.New(limiter.Config{
|
||||
Max: 20,
|
||||
Expiration: 30 * time.Second,
|
||||
LimiterMiddleware: limiter.SlidingWindow{},
|
||||
}))
|
||||
```
|
||||
|
||||
This means that every window will take into account the previous window(if there was any). The given formula for the rate is:
|
||||
```
|
||||
weightOfPreviousWindpw = previous window's amount request * (whenNewWindow / Expiration)
|
||||
rate = weightOfPreviousWindpw + current window's amount request.
|
||||
```
|
||||
|
||||
## Config
|
||||
|
||||
| Property | Type | Description | Default |
|
||||
|:-----------------------|:--------------------------|:--------------------------------------------------------------------------------------------|:-----------------------------------------|
|
||||
| Next | `func(*fiber.Ctx) bool` | Next defines a function to skip this middleware when returned true. | `nil` |
|
||||
| Max | `int` | Max number of recent connections during `Expiration` seconds before sending a 429 response. | 5 |
|
||||
| KeyGenerator | `func(*fiber.Ctx) string` | KeyGenerator allows you to generate custom keys, by default c.IP() is used. | A function using c.IP() as the default |
|
||||
| Expiration | `time.Duration` | Expiration is the time on how long to keep records of requests in memory. | 1 * time.Minute |
|
||||
| LimitReached | `fiber.Handler` | LimitReached is called when a request hits the limit. | A function sending 429 response |
|
||||
| SkipFailedRequests | `bool` | When set to true, requests with StatusCode >= 400 won't be counted. | false |
|
||||
| SkipSuccessfulRequests | `bool` | When set to true, requests with StatusCode < 400 won't be counted. | false |
|
||||
| Storage | `fiber.Storage` | Store is used to store the state of the middleware. | An in-memory store for this process only |
|
||||
| LimiterMiddleware | `LimiterHandler` | LimiterMiddleware is the struct that implements a limiter middleware. | A new Fixed Window Rate Limiter |
|
||||
| Duration (Deprecated) | `time.Duration` | Deprecated: Use Expiration instead | - |
|
||||
| Store (Deprecated) | `fiber.Storage` | Deprecated: Use Storage instead | - |
|
||||
| Key (Deprecated) | `func(*fiber.Ctx) string` | Deprecated: Use KeyGenerator instead | - |
|
||||
|
||||
:::note
|
||||
A custom store can be used if it implements the `Storage` interface - more details and an example can be found in `store.go`.
|
||||
:::
|
||||
|
||||
## Default Config
|
||||
|
||||
```go
|
||||
var ConfigDefault = Config{
|
||||
Max: 5,
|
||||
Expiration: 1 * time.Minute,
|
||||
KeyGenerator: func(c *fiber.Ctx) string {
|
||||
return c.IP()
|
||||
},
|
||||
LimitReached: func(c *fiber.Ctx) error {
|
||||
return c.SendStatus(fiber.StatusTooManyRequests)
|
||||
},
|
||||
SkipFailedRequests: false,
|
||||
SkipSuccessfulRequests: false,
|
||||
LimiterMiddleware: FixedWindow{},
|
||||
}
|
||||
```
|
||||
|
||||
### Custom Storage/Database
|
||||
|
||||
You can use any storage from our [storage](https://github.com/gofiber/storage/) package.
|
||||
|
||||
```go
|
||||
storage := sqlite3.New() // From github.com/gofiber/storage/sqlite3
|
||||
app.Use(limiter.New(limiter.Config{
|
||||
Storage: storage,
|
||||
}))
|
||||
```
|
168
docs/api/middleware/logger.md
Normal file
168
docs/api/middleware/logger.md
Normal file
|
@ -0,0 +1,168 @@
|
|||
---
|
||||
id: logger
|
||||
---
|
||||
|
||||
# Logger
|
||||
|
||||
Logger middleware for [Fiber](https://github.com/gofiber/fiber) that logs HTTP request/response details.
|
||||
|
||||
## Signatures
|
||||
```go
|
||||
func New(config ...Config) fiber.Handler
|
||||
```
|
||||
## Examples
|
||||
|
||||
Import the middleware package that is part of the Fiber web framework
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gofiber/fiber/v2/middleware/logger"
|
||||
)
|
||||
```
|
||||
|
||||
:::tip
|
||||
The order of registration plays a role. Only all routes that are registered after this one will be logged.
|
||||
The middleware should therefore be one of the first to be registered.
|
||||
:::
|
||||
|
||||
After you initiate your Fiber app, you can use the following possibilities:
|
||||
|
||||
```go
|
||||
// Initialize default config
|
||||
app.Use(logger.New())
|
||||
|
||||
// Or extend your config for customization
|
||||
// Logging remote IP and Port
|
||||
app.Use(logger.New(logger.Config{
|
||||
Format: "[${ip}]:${port} ${status} - ${method} ${path}\n",
|
||||
}))
|
||||
|
||||
// Logging Request ID
|
||||
app.Use(requestid.New())
|
||||
app.Use(logger.New(logger.Config{
|
||||
// For more options, see the Config section
|
||||
Format: "${pid} ${locals:requestid} ${status} - ${method} ${path}\n",
|
||||
}))
|
||||
|
||||
// Changing TimeZone & TimeFormat
|
||||
app.Use(logger.New(logger.Config{
|
||||
Format: "${pid} ${status} - ${method} ${path}\n",
|
||||
TimeFormat: "02-Jan-2006",
|
||||
TimeZone: "America/New_York",
|
||||
}))
|
||||
|
||||
// Custom File Writer
|
||||
file, err := os.OpenFile("./123.log", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
|
||||
if err != nil {
|
||||
log.Fatalf("error opening file: %v", err)
|
||||
}
|
||||
defer file.Close()
|
||||
app.Use(logger.New(logger.Config{
|
||||
Output: file,
|
||||
}))
|
||||
|
||||
// Add Custom Tags
|
||||
app.Use(logger.New(logger.Config{
|
||||
CustomTags: map[string]logger.LogFunc{
|
||||
"custom_tag": func(output logger.Buffer, c *fiber.Ctx, data *logger.Data, extraParam string) (int, error) {
|
||||
return output.WriteString("it is a custom tag")
|
||||
},
|
||||
},
|
||||
}))
|
||||
|
||||
// Callback after log is written
|
||||
app.Use(logger.New(logger.Config{
|
||||
TimeFormat: time.RFC3339Nano,
|
||||
TimeZone: "Asia/Shanghai",
|
||||
Done: func(c *fiber.Ctx, logString []byte) {
|
||||
if c.Response().StatusCode() != fiber.StatusOK {
|
||||
reporter.SendToSlack(logString)
|
||||
}
|
||||
},
|
||||
}))
|
||||
|
||||
// Disable colors when outputting to default format
|
||||
app.Use(logger.New(logger.Config{
|
||||
DisableColors: true,
|
||||
}))
|
||||
```
|
||||
|
||||
## Config
|
||||
|
||||
### Config
|
||||
|
||||
| Property | Type | Description | Default |
|
||||
|:-----------------|:---------------------------|:---------------------------------------------------------------------------------------------------------------------------------|:------------------------------------------------------------------------------------|
|
||||
| Next | `func(*fiber.Ctx) bool` | Next defines a function to skip this middleware when returned true. | `nil` |
|
||||
| Done | `func(*fiber.Ctx, []byte)` | Done is a function that is called after the log string for a request is written to Output, and pass the log string as parameter. | `nil` |
|
||||
| CustomTags | `map[string]LogFunc` | tagFunctions defines the custom tag action. | `map[string]LogFunc` |
|
||||
| Format | `string` | Format defines the logging tags. | `${time} \| ${status} \| ${latency} \| ${ip} \| ${method} \| ${path} \| ${error}\n` || TimeFormat | `string` | TimeFormat defines the time format for log timestamps. | `15:04:05` |
|
||||
| TimeZone | `string` | TimeZone can be specified, such as "UTC" and "America/New_York" and "Asia/Chongqing", etc | `"Local"` |
|
||||
| TimeInterval | `time.Duration` | TimeInterval is the delay before the timestamp is updated. | `500 * time.Millisecond` |
|
||||
| Output | `io.Writer` | Output is a writer where logs are written. | `os.Stdout` |
|
||||
| DisableColors | `bool` | DisableColors defines if the logs output should be colorized. | `false` |
|
||||
| enableColors | `bool` | Internal field for enabling colors in the log output. (This is not a user-configurable field) | - |
|
||||
| enableLatency | `bool` | Internal field for enabling latency measurement in logs. (This is not a user-configurable field) | - |
|
||||
| timeZoneLocation | `*time.Location` | Internal field for the time zone location. (This is not a user-configurable field) | - |
|
||||
|
||||
## Default Config
|
||||
```go
|
||||
var ConfigDefault = Config{
|
||||
Next: nil,
|
||||
Done: nil,
|
||||
Format: "${time} | ${status} | ${latency} | ${ip} | ${method} | ${path} | ${error}\n",
|
||||
TimeFormat: "15:04:05",
|
||||
TimeZone: "Local",
|
||||
TimeInterval: 500 * time.Millisecond,
|
||||
Output: os.Stdout,
|
||||
DisableColors: false,
|
||||
}
|
||||
```
|
||||
|
||||
## Constants
|
||||
```go
|
||||
// Logger variables
|
||||
const (
|
||||
TagPid = "pid"
|
||||
TagTime = "time"
|
||||
TagReferer = "referer"
|
||||
TagProtocol = "protocol"
|
||||
TagPort = "port"
|
||||
TagIP = "ip"
|
||||
TagIPs = "ips"
|
||||
TagHost = "host"
|
||||
TagMethod = "method"
|
||||
TagPath = "path"
|
||||
TagURL = "url"
|
||||
TagUA = "ua"
|
||||
TagLatency = "latency"
|
||||
TagStatus = "status" // response status
|
||||
TagResBody = "resBody" // response body
|
||||
TagReqHeaders = "reqHeaders"
|
||||
TagQueryStringParams = "queryParams" // request query parameters
|
||||
TagBody = "body" // request body
|
||||
TagBytesSent = "bytesSent"
|
||||
TagBytesReceived = "bytesReceived"
|
||||
TagRoute = "route"
|
||||
TagError = "error"
|
||||
// DEPRECATED: Use TagReqHeader instead
|
||||
TagHeader = "header:" // request header
|
||||
TagReqHeader = "reqHeader:" // request header
|
||||
TagRespHeader = "respHeader:" // response header
|
||||
TagQuery = "query:" // request query
|
||||
TagForm = "form:" // request form
|
||||
TagCookie = "cookie:" // request cookie
|
||||
TagLocals = "locals:"
|
||||
// colors
|
||||
TagBlack = "black"
|
||||
TagRed = "red"
|
||||
TagGreen = "green"
|
||||
TagYellow = "yellow"
|
||||
TagBlue = "blue"
|
||||
TagMagenta = "magenta"
|
||||
TagCyan = "cyan"
|
||||
TagWhite = "white"
|
||||
TagReset = "reset"
|
||||
)
|
||||
```
|
81
docs/api/middleware/monitor.md
Normal file
81
docs/api/middleware/monitor.md
Normal file
|
@ -0,0 +1,81 @@
|
|||
---
|
||||
id: monitor
|
||||
---
|
||||
|
||||
# Monitor
|
||||
|
||||
Monitor middleware for [Fiber](https://github.com/gofiber/fiber) that reports server metrics, inspired by [express-status-monitor](https://github.com/RafalWilinski/express-status-monitor)
|
||||
|
||||
:::caution
|
||||
|
||||
Monitor is still in beta, API might change in the future!
|
||||
|
||||
:::
|
||||
|
||||

|
||||
|
||||
### Signatures
|
||||
```go
|
||||
func New() fiber.Handler
|
||||
```
|
||||
|
||||
### Examples
|
||||
Import the middleware package that is part of the Fiber web framework
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gofiber/fiber/v2/middleware/monitor"
|
||||
)
|
||||
```
|
||||
|
||||
After you initiate your Fiber app, you can use the following possibilities:
|
||||
```go
|
||||
// Initialize default config (Assign the middleware to /metrics)
|
||||
app.Get("/metrics", monitor.New())
|
||||
|
||||
// Or extend your config for customization
|
||||
// Assign the middleware to /metrics
|
||||
// and change the Title to `MyService Metrics Page`
|
||||
app.Get("/metrics", monitor.New(monitor.Config{Title: "MyService Metrics Page"}))
|
||||
```
|
||||
You can also access the API endpoint with
|
||||
`curl -X GET -H "Accept: application/json" http://localhost:3000/metrics` which returns:
|
||||
```json
|
||||
{"pid":{ "cpu":0.4568381746582226, "ram":20516864, "conns":3 },
|
||||
"os": { "cpu":8.759124087593099, "ram":3997155328, "conns":44,
|
||||
"total_ram":8245489664, "load_avg":0.51 }}
|
||||
```
|
||||
|
||||
## Config
|
||||
|
||||
| Property | Type | Description | Default |
|
||||
|:-----------|:------------------------|:--------------------------------------------------------------------|:----------------------------------------------------------------------------|
|
||||
| Title | `string` | Metrics page title | "Fiber Monitor" |
|
||||
| Refresh | `time.Duration` | Refresh period | 3 seconds |
|
||||
| APIOnly | `bool` | Whether the service should expose only the monitoring API | false |
|
||||
| Next | `func(*fiber.Ctx) bool` | Next defines a function to skip this middleware when returned true. | `nil` |
|
||||
| CustomHead | `string` | Custom HTML Code to Head Section(Before End) | empty |
|
||||
| FontURL | `string` | FontURL for specify font resource path or URL | "https://fonts.googleapis.com/css2?family=Roboto:wght@400;900&display=swap" |
|
||||
| ChartJsURL | `string` | ChartJsURL for specify ChartJS library path or URL | "https://cdn.jsdelivr.net/npm/chart.js@2.9/dist/Chart.bundle.min.js" |
|
||||
|
||||
## Default Config
|
||||
|
||||
```go
|
||||
var ConfigDefault = Config{
|
||||
Title: defaultTitle,
|
||||
Refresh: defaultRefresh,
|
||||
FontURL: defaultFontURL,
|
||||
ChartJsURL: defaultChartJSURL,
|
||||
CustomHead: defaultCustomHead,
|
||||
APIOnly: false,
|
||||
Next: nil,
|
||||
index: newIndex(viewBag{
|
||||
defaultTitle,
|
||||
defaultRefresh,
|
||||
defaultFontURL,
|
||||
defaultChartJSURL,
|
||||
defaultCustomHead,
|
||||
}),
|
||||
}
|
||||
```
|
53
docs/api/middleware/pprof.md
Normal file
53
docs/api/middleware/pprof.md
Normal file
|
@ -0,0 +1,53 @@
|
|||
---
|
||||
id: pprof
|
||||
---
|
||||
|
||||
# Pprof
|
||||
|
||||
Pprof middleware for [Fiber](https://github.com/gofiber/fiber) that serves via its HTTP server runtime profiling data in the format expected by the pprof visualization tool. The package is typically only imported for the side effect of registering its HTTP handlers. The handled paths all begin with /debug/pprof/.
|
||||
|
||||
## Signatures
|
||||
|
||||
```go
|
||||
func New() fiber.Handler
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
Import the middleware package that is part of the Fiber web framework
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gofiber/fiber/v2/middleware/pprof"
|
||||
)
|
||||
```
|
||||
|
||||
After you initiate your Fiber app, you can use the following possibilities:
|
||||
|
||||
```go
|
||||
// Initialize default config
|
||||
app.Use(pprof.New())
|
||||
|
||||
// Or extend your config for customization
|
||||
|
||||
// For example, in systems where you have multiple ingress endpoints, it is common to add a URL prefix, like so:
|
||||
app.Use(pprof.New(pprof.Config{Prefix: "/endpoint-prefix"}))
|
||||
|
||||
// This prefix will be added to the default path of "/debug/pprof/", for a resulting URL of: "/endpoint-prefix/debug/pprof/".
|
||||
```
|
||||
|
||||
## Config
|
||||
|
||||
| Property | Type | Description | Default |
|
||||
|:---------|:------------------------|:------------------------------------------------------------------------------------------------------------------------------------------------|:--------|
|
||||
| Next | `func(*fiber.Ctx) bool` | Next defines a function to skip this middleware when returned true. | `nil` |
|
||||
| Prefix | `string` | Prefix defines a URL prefix added before "/debug/pprof". Note that it should start with (but not end with) a slash. Example: "/federated-fiber" | "" |
|
||||
|
||||
## Default Config
|
||||
|
||||
```go
|
||||
var ConfigDefault = Config{
|
||||
Next: nil,
|
||||
}
|
||||
```
|
165
docs/api/middleware/proxy.md
Normal file
165
docs/api/middleware/proxy.md
Normal file
|
@ -0,0 +1,165 @@
|
|||
---
|
||||
id: proxy
|
||||
---
|
||||
|
||||
# Proxy
|
||||
|
||||
Proxy middleware for [Fiber](https://github.com/gofiber/fiber) that allows you to proxy requests to multiple servers.
|
||||
|
||||
## Signatures
|
||||
|
||||
```go
|
||||
// Balancer create a load balancer among multiple upstrem servers.
|
||||
func Balancer(config Config) fiber.Handler
|
||||
// Forward performs the given http request and fills the given http response.
|
||||
func Forward(addr string, clients ...*fasthttp.Client) fiber.Handler
|
||||
// Do performs the given http request and fills the given http response.
|
||||
func Do(c *fiber.Ctx, addr string, clients ...*fasthttp.Client) error
|
||||
// DoRedirects performs the given http request and fills the given http response while following up to maxRedirectsCount redirects.
|
||||
func DoRedirects(c *fiber.Ctx, addr string, maxRedirectsCount int, clients ...*fasthttp.Client) error
|
||||
// DoDeadline performs the given request and waits for response until the given deadline.
|
||||
func DoDeadline(c *fiber.Ctx, addr string, deadline time.Time, clients ...*fasthttp.Client) error
|
||||
// DoTimeout performs the given request and waits for response during the given timeout duration.
|
||||
func DoTimeout(c *fiber.Ctx, addr string, timeout time.Duration, clients ...*fasthttp.Client) error
|
||||
// DomainForward the given http request based on the given domain and fills the given http response
|
||||
func DomainForward(hostname string, addr string, clients ...*fasthttp.Client) fiber.Handler
|
||||
// BalancerForward performs the given http request based round robin balancer and fills the given http response
|
||||
func BalancerForward(servers []string, clients ...*fasthttp.Client) fiber.Handler
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
Import the middleware package that is part of the Fiber web framework
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gofiber/fiber/v2/middleware/proxy"
|
||||
)
|
||||
```
|
||||
|
||||
After you initiate your Fiber app, you can use the following possibilities:
|
||||
|
||||
```go
|
||||
// if target https site uses a self-signed certificate, you should
|
||||
// call WithTlsConfig before Do and Forward
|
||||
proxy.WithTlsConfig(&tls.Config{
|
||||
InsecureSkipVerify: true,
|
||||
})
|
||||
// if you need to use global self-custom client, you should use proxy.WithClient.
|
||||
proxy.WithClient(&fasthttp.Client{
|
||||
NoDefaultUserAgentHeader: true,
|
||||
DisablePathNormalizing: true,
|
||||
})
|
||||
|
||||
// Forward to url
|
||||
app.Get("/gif", proxy.Forward("https://i.imgur.com/IWaBepg.gif"))
|
||||
|
||||
// If you want to forward with a specific domain. You have to use proxy.DomainForward.
|
||||
app.Get("/payments", proxy.DomainForward("docs.gofiber.io", "http://localhost:8000"))
|
||||
|
||||
// Forward to url with local custom client
|
||||
app.Get("/gif", proxy.Forward("https://i.imgur.com/IWaBepg.gif", &fasthttp.Client{
|
||||
NoDefaultUserAgentHeader: true,
|
||||
DisablePathNormalizing: true,
|
||||
}))
|
||||
|
||||
// Make request within handler
|
||||
app.Get("/:id", func(c *fiber.Ctx) error {
|
||||
url := "https://i.imgur.com/"+c.Params("id")+".gif"
|
||||
if err := proxy.Do(c, url); err != nil {
|
||||
return err
|
||||
}
|
||||
// Remove Server header from response
|
||||
c.Response().Header.Del(fiber.HeaderServer)
|
||||
return nil
|
||||
})
|
||||
|
||||
// Make proxy requests while following redirects
|
||||
app.Get("/proxy", func(c *fiber.Ctx) error {
|
||||
if err := proxy.DoRedirects(c, "http://google.com", 3); err != nil {
|
||||
return err
|
||||
}
|
||||
// Remove Server header from response
|
||||
c.Response().Header.Del(fiber.HeaderServer)
|
||||
return nil
|
||||
})
|
||||
|
||||
// Make proxy requests and wait up to 5 seconds before timing out
|
||||
app.Get("/proxy", func(c *fiber.Ctx) error {
|
||||
if err := proxy.DoTimeout(c, "http://localhost:3000", time.Second * 5); err != nil {
|
||||
return err
|
||||
}
|
||||
// Remove Server header from response
|
||||
c.Response().Header.Del(fiber.HeaderServer)
|
||||
return nil
|
||||
})
|
||||
|
||||
// Make proxy requests, timeout a minute from now
|
||||
app.Get("/proxy", func(c *fiber.Ctx) error {
|
||||
if err := proxy.DoDeadline(c, "http://localhost", time.Now().Add(time.Minute)); err != nil {
|
||||
return err
|
||||
}
|
||||
// Remove Server header from response
|
||||
c.Response().Header.Del(fiber.HeaderServer)
|
||||
return nil
|
||||
})
|
||||
|
||||
// Minimal round robin balancer
|
||||
app.Use(proxy.Balancer(proxy.Config{
|
||||
Servers: []string{
|
||||
"http://localhost:3001",
|
||||
"http://localhost:3002",
|
||||
"http://localhost:3003",
|
||||
},
|
||||
}))
|
||||
|
||||
// Or extend your balancer for customization
|
||||
app.Use(proxy.Balancer(proxy.Config{
|
||||
Servers: []string{
|
||||
"http://localhost:3001",
|
||||
"http://localhost:3002",
|
||||
"http://localhost:3003",
|
||||
},
|
||||
ModifyRequest: func(c *fiber.Ctx) error {
|
||||
c.Request().Header.Add("X-Real-IP", c.IP())
|
||||
return nil
|
||||
},
|
||||
ModifyResponse: func(c *fiber.Ctx) error {
|
||||
c.Response().Header.Del(fiber.HeaderServer)
|
||||
return nil
|
||||
},
|
||||
}))
|
||||
|
||||
// Or this way if the balancer is using https and the destination server is only using http.
|
||||
app.Use(proxy.BalancerForward([]string{
|
||||
"http://localhost:3001",
|
||||
"http://localhost:3002",
|
||||
"http://localhost:3003",
|
||||
}))
|
||||
```
|
||||
|
||||
## Config
|
||||
|
||||
| Property | Type | Description | Default |
|
||||
|:----------------|:-----------------------------------------------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:----------------|
|
||||
| Next | `func(*fiber.Ctx) bool` | Next defines a function to skip this middleware when returned true. | `nil` |
|
||||
| Servers | `[]string` | Servers defines a list of `<scheme>://<host>` HTTP servers, which are used in a round-robin manner. i.e.: "https://foobar.com, http://www.foobar.com" | (Required) |
|
||||
| ModifyRequest | `fiber.Handler` | ModifyRequest allows you to alter the request. | `nil` |
|
||||
| ModifyResponse | `fiber.Handler` | ModifyResponse allows you to alter the response. | `nil` |
|
||||
| Timeout | `time.Duration` | Timeout is the request timeout used when calling the proxy client. | 1 second |
|
||||
| ReadBufferSize | `int` | Per-connection buffer size for requests' reading. This also limits the maximum header size. Increase this buffer if your clients send multi-KB RequestURIs and/or multi-KB headers (for example, BIG cookies). | (Not specified) |
|
||||
| WriteBufferSize | `int` | Per-connection buffer size for responses' writing. | (Not specified) |
|
||||
| TlsConfig | `*tls.Config` (or `*fasthttp.TLSConfig` in v3) | TLS config for the HTTP client. | `nil` |
|
||||
| Client | `*fasthttp.LBClient` | Client is a custom client when client config is complex. | `nil` |
|
||||
|
||||
## Default Config
|
||||
|
||||
```go
|
||||
var ConfigDefault = Config{
|
||||
Next: nil,
|
||||
ModifyRequest: nil,
|
||||
ModifyResponse: nil,
|
||||
Timeout: fasthttp.DefaultLBClientTimeout,
|
||||
}
|
||||
```
|
54
docs/api/middleware/recover.md
Normal file
54
docs/api/middleware/recover.md
Normal file
|
@ -0,0 +1,54 @@
|
|||
---
|
||||
id: recover
|
||||
---
|
||||
|
||||
# Recover
|
||||
|
||||
Recover middleware for [Fiber](https://github.com/gofiber/fiber) that recovers from panics anywhere in the stack chain and handles the control to the centralized [ErrorHandler](https://docs.gofiber.io/guide/error-handling).
|
||||
|
||||
## Signatures
|
||||
|
||||
```go
|
||||
func New(config ...Config) fiber.Handler
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
Import the middleware package that is part of the Fiber web framework
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gofiber/fiber/v2/middleware/recover"
|
||||
)
|
||||
```
|
||||
|
||||
After you initiate your Fiber app, you can use the following possibilities:
|
||||
|
||||
```go
|
||||
// Initialize default config
|
||||
app.Use(recover.New())
|
||||
|
||||
// This panic will be caught by the middleware
|
||||
app.Get("/", func(c *fiber.Ctx) error {
|
||||
panic("I'm an error")
|
||||
})
|
||||
```
|
||||
|
||||
## Config
|
||||
|
||||
| Property | Type | Description | Default |
|
||||
|:------------------|:--------------------------------|:--------------------------------------------------------------------|:-------------------------|
|
||||
| Next | `func(*fiber.Ctx) bool` | Next defines a function to skip this middleware when returned true. | `nil` |
|
||||
| EnableStackTrace | `bool` | EnableStackTrace enables handling stack trace. | `false` |
|
||||
| StackTraceHandler | `func(*fiber.Ctx, interface{})` | StackTraceHandler defines a function to handle stack trace. | defaultStackTraceHandler |
|
||||
|
||||
## Default Config
|
||||
|
||||
```go
|
||||
var ConfigDefault = Config{
|
||||
Next: nil,
|
||||
EnableStackTrace: false,
|
||||
StackTraceHandler: defaultStackTraceHandler,
|
||||
}
|
||||
```
|
68
docs/api/middleware/redirect.md
Normal file
68
docs/api/middleware/redirect.md
Normal file
|
@ -0,0 +1,68 @@
|
|||
---
|
||||
id: redirect
|
||||
---
|
||||
|
||||
# Redirect
|
||||
|
||||
Redirection middleware for Fiber.
|
||||
|
||||
## Signatures
|
||||
|
||||
```go
|
||||
func New(config ...Config) fiber.Handler
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gofiber/fiber/v2/middleware/redirect"
|
||||
)
|
||||
|
||||
func main() {
|
||||
app := fiber.New()
|
||||
|
||||
app.Use(redirect.New(redirect.Config{
|
||||
Rules: map[string]string{
|
||||
"/old": "/new",
|
||||
"/old/*": "/new/$1",
|
||||
},
|
||||
StatusCode: 301,
|
||||
}))
|
||||
|
||||
app.Get("/new", func(c *fiber.Ctx) error {
|
||||
return c.SendString("Hello, World!")
|
||||
})
|
||||
app.Get("/new/*", func(c *fiber.Ctx) error {
|
||||
return c.SendString("Wildcard: " + c.Params("*"))
|
||||
})
|
||||
|
||||
app.Listen(":3000")
|
||||
}
|
||||
```
|
||||
|
||||
**Test:**
|
||||
|
||||
```curl
|
||||
curl http://localhost:3000/old
|
||||
curl http://localhost:3000/old/hello
|
||||
```
|
||||
|
||||
## Config
|
||||
|
||||
| Property | Type | Description | Default |
|
||||
|:-----------|:------------------------|:---------------------------------------------------------------------------------------------------------------------------|:-----------------------|
|
||||
| Next | `func(*fiber.Ctx) bool` | Filter defines a function to skip middleware. | `nil` |
|
||||
| Rules | `map[string]string` | Rules defines the URL path rewrite rules. The values captured in asterisk can be retrieved by index e.g. $1, $2 and so on. | Required |
|
||||
| StatusCode | `int` | The status code when redirecting. This is ignored if Redirect is disabled. | 302 Temporary Redirect |
|
||||
|
||||
## Default Config
|
||||
|
||||
```go
|
||||
var ConfigDefault = Config{
|
||||
StatusCode: fiber.StatusFound,
|
||||
}
|
||||
```
|
62
docs/api/middleware/requestid.md
Normal file
62
docs/api/middleware/requestid.md
Normal file
|
@ -0,0 +1,62 @@
|
|||
---
|
||||
id: requestid
|
||||
---
|
||||
|
||||
# RequestID
|
||||
|
||||
RequestID middleware for [Fiber](https://github.com/gofiber/fiber) that adds an identifier to the response.
|
||||
|
||||
## Signatures
|
||||
|
||||
```go
|
||||
func New(config ...Config) fiber.Handler
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
Import the middleware package that is part of the Fiber web framework
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gofiber/fiber/v2/middleware/requestid"
|
||||
)
|
||||
```
|
||||
|
||||
After you initiate your Fiber app, you can use the following possibilities:
|
||||
|
||||
```go
|
||||
// Initialize default config
|
||||
app.Use(requestid.New())
|
||||
|
||||
// Or extend your config for customization
|
||||
app.Use(requestid.New(requestid.Config{
|
||||
Header: "X-Custom-Header",
|
||||
Generator: func() string {
|
||||
return "static-id"
|
||||
},
|
||||
}))
|
||||
```
|
||||
|
||||
## Config
|
||||
|
||||
| Property | Type | Description | Default |
|
||||
|:-----------|:------------------------|:--------------------------------------------------------------------------------------------------|:---------------|
|
||||
| Next | `func(*fiber.Ctx) bool` | Next defines a function to skip this middleware when returned true. | `nil` |
|
||||
| Header | `string` | Header is the header key where to get/set the unique request ID. | "X-Request-ID" |
|
||||
| Generator | `func() string` | Generator defines a function to generate the unique identifier. | utils.UUID |
|
||||
| ContextKey | `interface{}` | ContextKey defines the key used when storing the request ID in the locals for a specific request. | "requestid" |
|
||||
|
||||
## Default Config
|
||||
The default config uses a fast UUID generator which will expose the number of
|
||||
requests made to the server. To conceal this value for better privacy, use the
|
||||
`utils.UUIDv4` generator.
|
||||
|
||||
```go
|
||||
var ConfigDefault = Config{
|
||||
Next: nil,
|
||||
Header: fiber.HeaderXRequestID,
|
||||
Generator: utils.UUID,
|
||||
ContextKey: "requestid",
|
||||
}
|
||||
```
|
58
docs/api/middleware/rewrite.md
Normal file
58
docs/api/middleware/rewrite.md
Normal file
|
@ -0,0 +1,58 @@
|
|||
---
|
||||
id: rewrite
|
||||
---
|
||||
|
||||
# Rewrite
|
||||
|
||||
Rewrite middleware rewrites the URL path based on provided rules. It can be helpful for backward compatibility or just creating cleaner and more descriptive links.
|
||||
|
||||
## Signatures
|
||||
|
||||
```go
|
||||
func New(config ...Config) fiber.Handler
|
||||
```
|
||||
|
||||
## Config
|
||||
|
||||
| Property | Type | Description | Default |
|
||||
|:---------|:------------------------|:-----------------------------------------------------------------------------------------------------|:-----------|
|
||||
| Next | `func(*fiber.Ctx) bool` | Next defines a function to skip middleware. | `nil` |
|
||||
| Rules | `map[string]string` | Rules defines the URL path rewrite rules. The values captured in asterisk can be retrieved by index. | (Required) |
|
||||
|
||||
### Examples
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gofiber/fiber/v2/middleware/rewrite"
|
||||
)
|
||||
|
||||
func main() {
|
||||
app := fiber.New()
|
||||
|
||||
app.Use(rewrite.New(rewrite.Config{
|
||||
Rules: map[string]string{
|
||||
"/old": "/new",
|
||||
"/old/*": "/new/$1",
|
||||
},
|
||||
}))
|
||||
|
||||
app.Get("/new", func(c *fiber.Ctx) error {
|
||||
return c.SendString("Hello, World!")
|
||||
})
|
||||
app.Get("/new/*", func(c *fiber.Ctx) error {
|
||||
return c.SendString("Wildcard: " + c.Params("*"))
|
||||
})
|
||||
|
||||
app.Listen(":3000")
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
**Test:**
|
||||
|
||||
```curl
|
||||
curl http://localhost:3000/old
|
||||
curl http://localhost:3000/old/hello
|
||||
```
|
139
docs/api/middleware/session.md
Normal file
139
docs/api/middleware/session.md
Normal file
|
@ -0,0 +1,139 @@
|
|||
---
|
||||
id: session
|
||||
---
|
||||
|
||||
# Session
|
||||
|
||||
Session middleware for [Fiber](https://github.com/gofiber/fiber).
|
||||
|
||||
:::note
|
||||
This middleware uses our [Storage](https://github.com/gofiber/storage) package to support various databases through a single interface. The default configuration for this middleware saves data to memory, see the examples below for other databases.
|
||||
:::
|
||||
|
||||
## Signatures
|
||||
|
||||
```go
|
||||
func New(config ...Config) *Store
|
||||
func (s *Store) RegisterType(i interface{})
|
||||
func (s *Store) Get(c *fiber.Ctx) (*Session, error)
|
||||
func (s *Store) Delete(id string) error
|
||||
func (s *Store) Reset() error
|
||||
|
||||
func (s *Session) Get(key string) interface{}
|
||||
func (s *Session) Set(key string, val interface{})
|
||||
func (s *Session) Delete(key string)
|
||||
func (s *Session) Destroy() error
|
||||
func (s *Session) Reset() error
|
||||
func (s *Session) Regenerate() error
|
||||
func (s *Session) Save() error
|
||||
func (s *Session) Fresh() bool
|
||||
func (s *Session) ID() string
|
||||
func (s *Session) Keys() []string
|
||||
```
|
||||
|
||||
:::caution
|
||||
Storing `interface{}` values are limited to built-ins Go types.
|
||||
:::
|
||||
|
||||
## Examples
|
||||
Import the middleware package that is part of the Fiber web framework
|
||||
```go
|
||||
import (
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gofiber/fiber/v2/middleware/session"
|
||||
)
|
||||
```
|
||||
|
||||
After you initiate your Fiber app, you can use the following possibilities:
|
||||
|
||||
```go
|
||||
// Initialize default config
|
||||
// This stores all of your app's sessions
|
||||
store := session.New()
|
||||
|
||||
app.Get("/", func(c *fiber.Ctx) error {
|
||||
// Get session from storage
|
||||
sess, err := store.Get(c)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Get value
|
||||
name := sess.Get("name")
|
||||
|
||||
// Set key/value
|
||||
sess.Set("name", "john")
|
||||
|
||||
// Get all Keys
|
||||
keys := sess.Keys()
|
||||
|
||||
// Delete key
|
||||
sess.Delete("name")
|
||||
|
||||
// Destroy session
|
||||
if err := sess.Destroy(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Sets a specific expiration for this session
|
||||
sess.SetExpiry(time.Second * 2)
|
||||
|
||||
// Save session
|
||||
if err := sess.Save(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return c.SendString(fmt.Sprintf("Welcome %v", name))
|
||||
})
|
||||
```
|
||||
|
||||
## Config
|
||||
|
||||
| Property | Type | Description | Default |
|
||||
|:------------------------|:----------------|:------------------------------------------------------------------------------------------------------------|:----------------------|
|
||||
| Expiration | `time.Duration` | Allowed session duration. | `24 * time.Hour` |
|
||||
| Storage | `fiber.Storage` | Storage interface to store the session data. | `memory.New()` |
|
||||
| KeyLookup | `string` | KeyLookup is a string in the form of "`<source>:<name>`" that is used to extract session id from the request. | `"cookie:session_id"` |
|
||||
| CookieDomain | `string` | Domain of the cookie. | `""` |
|
||||
| CookiePath | `string` | Path of the cookie. | `""` |
|
||||
| CookieSecure | `bool` | Indicates if cookie is secure. | `false` |
|
||||
| CookieHTTPOnly | `bool` | Indicates if cookie is HTTP only. | `false` |
|
||||
| CookieSameSite | `string` | Value of SameSite cookie. | `"Lax"` |
|
||||
| CookieSessionOnly | `bool` | Decides whether cookie should last for only the browser session. Ignores Expiration if set to true. | `false` |
|
||||
| KeyGenerator | `func() string` | KeyGenerator generates the session key. | `utils.UUIDv4` |
|
||||
| CookieName (Deprecated) | `string` | Deprecated: Please use KeyLookup. The session name. | `""` |
|
||||
|
||||
## Default Config
|
||||
|
||||
```go
|
||||
var ConfigDefault = Config{
|
||||
Expiration: 24 * time.Hour,
|
||||
KeyLookup: "cookie:session_id",
|
||||
KeyGenerator: utils.UUIDv4,
|
||||
source: "cookie",
|
||||
sessionName: "session_id",
|
||||
}
|
||||
```
|
||||
|
||||
## Constants
|
||||
|
||||
```go
|
||||
const (
|
||||
SourceCookie Source = "cookie"
|
||||
SourceHeader Source = "header"
|
||||
SourceURLQuery Source = "query"
|
||||
)
|
||||
```
|
||||
|
||||
### Custom Storage/Database
|
||||
|
||||
You can use any storage from our [storage](https://github.com/gofiber/storage/) package.
|
||||
|
||||
```go
|
||||
storage := sqlite3.New() // From github.com/gofiber/storage/sqlite3
|
||||
store := session.New(session.Config{
|
||||
Storage: storage,
|
||||
})
|
||||
```
|
||||
|
||||
To use the store, see the [Examples](#examples).
|
47
docs/api/middleware/skip.md
Normal file
47
docs/api/middleware/skip.md
Normal file
|
@ -0,0 +1,47 @@
|
|||
---
|
||||
id: skip
|
||||
---
|
||||
|
||||
# Skip
|
||||
|
||||
Skip middleware for [Fiber](https://github.com/gofiber/fiber) that skips a wrapped handler if a predicate is true.
|
||||
|
||||
## Signatures
|
||||
```go
|
||||
func New(handler fiber.Handler, exclude func(c *fiber.Ctx) bool) fiber.Handler
|
||||
```
|
||||
|
||||
## Examples
|
||||
Import the middleware package that is part of the Fiber web framework
|
||||
```go
|
||||
import (
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gofiber/fiber/v2/middleware/skip"
|
||||
)
|
||||
```
|
||||
|
||||
After you initiate your Fiber app, you can use the following possibilities:
|
||||
|
||||
```go
|
||||
func main() {
|
||||
app := fiber.New()
|
||||
|
||||
app.Use(skip.New(BasicHandler, func(ctx *fiber.Ctx) bool {
|
||||
return ctx.Method() == fiber.MethodGet
|
||||
}))
|
||||
|
||||
app.Get("/", func(ctx *fiber.Ctx) error {
|
||||
return ctx.SendString("It was a GET request!")
|
||||
})
|
||||
|
||||
log.Fatal(app.Listen(":3000"))
|
||||
}
|
||||
|
||||
func BasicHandler(ctx *fiber.Ctx) error {
|
||||
return ctx.SendString("It was not a GET request!")
|
||||
}
|
||||
```
|
||||
|
||||
:::tip
|
||||
app.Use will handle requests from any route, and any method. In the example above, it will only skip if the method is GET.
|
||||
:::
|
146
docs/api/middleware/timeout.md
Normal file
146
docs/api/middleware/timeout.md
Normal file
|
@ -0,0 +1,146 @@
|
|||
---
|
||||
id: timeout
|
||||
---
|
||||
|
||||
# Timeout
|
||||
|
||||
There exist two distinct implementations of timeout middleware [Fiber](https://github.com/gofiber/fiber).
|
||||
|
||||
**New**
|
||||
|
||||
Wraps a `fiber.Handler` with a timeout. If the handler takes longer than the given duration to return, the timeout error is set and forwarded to the centralized [ErrorHandler](https://docs.gofiber.io/error-handling).
|
||||
|
||||
:::caution
|
||||
This has been deprecated since it raises race conditions.
|
||||
:::
|
||||
|
||||
**NewWithContext**
|
||||
|
||||
As a `fiber.Handler` wrapper, it creates a context with `context.WithTimeout` and pass it in `UserContext`.
|
||||
|
||||
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`.
|
||||
|
||||
|
||||
It does not cancel long running executions. Underlying executions must handle timeout by using `context.Context` parameter.
|
||||
|
||||
## Signatures
|
||||
|
||||
```go
|
||||
func New(handler fiber.Handler, timeout time.Duration, timeoutErrors ...error) fiber.Handler
|
||||
func NewWithContext(handler fiber.Handler, timeout time.Duration, timeoutErrors ...error) fiber.Handler
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
Import the middleware package that is part of the Fiber web framework
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gofiber/fiber/v2/middleware/timeout"
|
||||
)
|
||||
```
|
||||
|
||||
After you initiate your Fiber app, you can use the following possibilities:
|
||||
|
||||
```go
|
||||
func main() {
|
||||
app := fiber.New()
|
||||
|
||||
h := func(c *fiber.Ctx) error {
|
||||
sleepTime, _ := time.ParseDuration(c.Params("sleepTime") + "ms")
|
||||
if err := sleepWithContext(c.UserContext(), sleepTime); err != nil {
|
||||
return fmt.Errorf("%w: execution error", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
app.Get("/foo/:sleepTime", timeout.New(h, 2*time.Second))
|
||||
log.Fatal(app.Listen(":3000"))
|
||||
}
|
||||
|
||||
func sleepWithContext(ctx context.Context, d time.Duration) error {
|
||||
timer := time.NewTimer(d)
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
if !timer.Stop() {
|
||||
<-timer.C
|
||||
}
|
||||
return context.DeadlineExceeded
|
||||
case <-timer.C:
|
||||
}
|
||||
return nil
|
||||
}
|
||||
```
|
||||
|
||||
Test http 200 with curl:
|
||||
|
||||
```bash
|
||||
curl --location -I --request GET 'http://localhost:3000/foo/1000'
|
||||
```
|
||||
|
||||
Test http 408 with curl:
|
||||
|
||||
```bash
|
||||
curl --location -I --request GET 'http://localhost:3000/foo/3000'
|
||||
```
|
||||
|
||||
Use with custom error:
|
||||
|
||||
```go
|
||||
var ErrFooTimeOut = errors.New("foo context canceled")
|
||||
|
||||
func main() {
|
||||
app := fiber.New()
|
||||
h := func(c *fiber.Ctx) error {
|
||||
sleepTime, _ := time.ParseDuration(c.Params("sleepTime") + "ms")
|
||||
if err := sleepWithContextWithCustomError(c.UserContext(), sleepTime); err != nil {
|
||||
return fmt.Errorf("%w: execution error", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
app.Get("/foo/:sleepTime", timeout.NewWithContext(h, 2*time.Second, ErrFooTimeOut))
|
||||
log.Fatal(app.Listen(":3000"))
|
||||
}
|
||||
|
||||
func sleepWithContextWithCustomError(ctx context.Context, d time.Duration) error {
|
||||
timer := time.NewTimer(d)
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
if !timer.Stop() {
|
||||
<-timer.C
|
||||
}
|
||||
return ErrFooTimeOut
|
||||
case <-timer.C:
|
||||
}
|
||||
return nil
|
||||
}
|
||||
```
|
||||
|
||||
Sample usage with a DB call:
|
||||
|
||||
```go
|
||||
func main() {
|
||||
app := fiber.New()
|
||||
db, _ := gorm.Open(postgres.Open("postgres://localhost/foodb"), &gorm.Config{})
|
||||
|
||||
handler := func(ctx *fiber.Ctx) error {
|
||||
tran := db.WithContext(ctx.UserContext()).Begin()
|
||||
|
||||
if tran = tran.Exec("SELECT pg_sleep(50)"); tran.Error != nil {
|
||||
return tran.Error
|
||||
}
|
||||
|
||||
if tran = tran.Commit(); tran.Error != nil {
|
||||
return tran.Error
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
app.Get("/foo", timeout.NewWithContext(handler, 10*time.Second))
|
||||
log.Fatal(app.Listen(":3000"))
|
||||
}
|
||||
```
|
Loading…
Add table
Add a link
Reference in a new issue