mirror of https://github.com/gofiber/fiber.git
Merge remote-tracking branch 'origin/main'
commit
0fbb447679
|
@ -39,7 +39,7 @@ Fiber v3 is currently in beta and under active development. While it offers exci
|
||||||
|
|
||||||
## ⚙️ Installation
|
## ⚙️ Installation
|
||||||
|
|
||||||
Fiber requires **Go version `1.21` or higher** to run. If you need to install or upgrade Go, visit the [official Go download page](https://go.dev/dl/). To start setting up your project. Create a new directory for your project and navigate into it. Then, initialize your project with Go modules by executing the following command in your terminal:
|
Fiber requires **Go version `1.22` or higher** to run. If you need to install or upgrade Go, visit the [official Go download page](https://go.dev/dl/). To start setting up your project. Create a new directory for your project and navigate into it. Then, initialize your project with Go modules by executing the following command in your terminal:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
go mod init github.com/your/repo
|
go mod init github.com/your/repo
|
||||||
|
@ -124,7 +124,7 @@ We **listen** to our users in [issues](https://github.com/gofiber/fiber/issues),
|
||||||
|
|
||||||
## ⚠️ Limitations
|
## ⚠️ Limitations
|
||||||
|
|
||||||
- Due to Fiber's usage of unsafe, the library may not always be compatible with the latest Go version. Fiber v3 has been tested with Go versions 1.21 and 1.22.
|
- Due to Fiber's usage of unsafe, the library may not always be compatible with the latest Go version. Fiber v3 has been tested with Go versions 1.22 and 1.23.
|
||||||
- Fiber is not compatible with net/http interfaces. This means you will not be able to use projects like gqlgen, go-swagger, or any others which are part of the net/http ecosystem.
|
- Fiber is not compatible with net/http interfaces. This means you will not be able to use projects like gqlgen, go-swagger, or any others which are part of the net/http ecosystem.
|
||||||
|
|
||||||
## 👀 Examples
|
## 👀 Examples
|
||||||
|
@ -615,7 +615,7 @@ List of externally hosted middleware modules and maintained by the [Fiber team](
|
||||||
| :------------------------------------------------ | :-------------------------------------------------------------------------------------------------------------------- |
|
| :------------------------------------------------ | :-------------------------------------------------------------------------------------------------------------------- |
|
||||||
| [contrib](https://github.com/gofiber/contrib) | Third party middlewares |
|
| [contrib](https://github.com/gofiber/contrib) | Third party middlewares |
|
||||||
| [storage](https://github.com/gofiber/storage) | Premade storage drivers that implement the Storage interface, designed to be used with various Fiber middlewares. |
|
| [storage](https://github.com/gofiber/storage) | Premade storage drivers that implement the Storage interface, designed to be used with various Fiber middlewares. |
|
||||||
| [template](https://github.com/gofiber/template) | This package contains 9 template engines that can be used with Fiber `v3` Go version 1.21 or higher is required. |
|
| [template](https://github.com/gofiber/template) | This package contains 9 template engines that can be used with Fiber `v3` Go version 1.22 or higher is required. |
|
||||||
|
|
||||||
## 🕶️ Awesome List
|
## 🕶️ Awesome List
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,7 @@ jobs:
|
||||||
uses: actions/setup-go@v5
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
# NOTE: Keep this in sync with the version from go.mod
|
# NOTE: Keep this in sync with the version from go.mod
|
||||||
go-version: "1.21.x"
|
go-version: "1.22.x"
|
||||||
|
|
||||||
- name: Run Benchmark
|
- name: Run Benchmark
|
||||||
run: set -o pipefail; go test ./... -benchmem -run=^$ -bench . | tee output.txt
|
run: set -o pipefail; go test ./... -benchmem -run=^$ -bench . | tee output.txt
|
||||||
|
|
|
@ -30,11 +30,11 @@ jobs:
|
||||||
- uses: actions/setup-go@v5
|
- uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
# NOTE: Keep this in sync with the version from go.mod
|
# NOTE: Keep this in sync with the version from go.mod
|
||||||
go-version: "1.21.x"
|
go-version: "1.22.x"
|
||||||
cache: false
|
cache: false
|
||||||
|
|
||||||
- name: golangci-lint
|
- name: golangci-lint
|
||||||
uses: golangci/golangci-lint-action@v6
|
uses: golangci/golangci-lint-action@v6
|
||||||
with:
|
with:
|
||||||
# NOTE: Keep this in sync with the version from .golangci.yml
|
# NOTE: Keep this in sync with the version from .golangci.yml
|
||||||
version: v1.59.1
|
version: v1.60.1
|
||||||
|
|
|
@ -25,7 +25,7 @@ jobs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repo
|
- name: Checkout repo
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Checkout dependabot
|
- name: Checkout dependabot
|
||||||
run: |
|
run: |
|
||||||
|
|
|
@ -15,8 +15,8 @@ jobs:
|
||||||
unit:
|
unit:
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
go-version: [1.21.x, 1.22.x]
|
go-version: [1.22.x, 1.23.x]
|
||||||
platform: [ubuntu-latest, windows-latest, macos-latest, macos-14]
|
platform: [ubuntu-latest, windows-latest, macos-latest, macos-13]
|
||||||
runs-on: ${{ matrix.platform }}
|
runs-on: ${{ matrix.platform }}
|
||||||
steps:
|
steps:
|
||||||
- name: Fetch Repository
|
- name: Fetch Repository
|
||||||
|
@ -31,7 +31,7 @@ jobs:
|
||||||
run: go run gotest.tools/gotestsum@latest -f testname -- ./... -race -count=1 -coverprofile=coverage.txt -covermode=atomic -shuffle=on
|
run: go run gotest.tools/gotestsum@latest -f testname -- ./... -race -count=1 -coverprofile=coverage.txt -covermode=atomic -shuffle=on
|
||||||
|
|
||||||
- name: Upload coverage reports to Codecov
|
- name: Upload coverage reports to Codecov
|
||||||
if: ${{ matrix.platform == 'ubuntu-latest' && matrix.go-version == '1.22.x' }}
|
if: ${{ matrix.platform == 'ubuntu-latest' && matrix.go-version == '1.23.x' }}
|
||||||
uses: codecov/codecov-action@v4.5.0
|
uses: codecov/codecov-action@v4.5.0
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.CODECOV_TOKEN }}
|
token: ${{ secrets.CODECOV_TOKEN }}
|
||||||
|
|
11
Makefile
11
Makefile
|
@ -35,7 +35,7 @@ markdown:
|
||||||
## lint: 🚨 Run lint checks
|
## lint: 🚨 Run lint checks
|
||||||
.PHONY: lint
|
.PHONY: lint
|
||||||
lint:
|
lint:
|
||||||
go run github.com/golangci/golangci-lint/cmd/golangci-lint@v1.59.1 run ./...
|
go run github.com/golangci/golangci-lint/cmd/golangci-lint@v1.60.1 run ./...
|
||||||
|
|
||||||
## test: 🚦 Execute all tests
|
## test: 🚦 Execute all tests
|
||||||
.PHONY: test
|
.PHONY: test
|
||||||
|
@ -56,3 +56,12 @@ tidy:
|
||||||
.PHONY: betteralign
|
.PHONY: betteralign
|
||||||
betteralign:
|
betteralign:
|
||||||
go run github.com/dkorunic/betteralign/cmd/betteralign@latest -test_files -generated_files -apply ./...
|
go run github.com/dkorunic/betteralign/cmd/betteralign@latest -test_files -generated_files -apply ./...
|
||||||
|
|
||||||
|
## tidy: ⚡️ Generate msgp
|
||||||
|
.PHONY: msgp
|
||||||
|
msgp:
|
||||||
|
go run github.com/tinylib/msgp@latest -file="middleware/cache/manager.go" -o="middleware/cache/manager_msgp.go" -tests=true -unexported
|
||||||
|
go run github.com/tinylib/msgp@latest -file="middleware/session/data.go" -o="middleware/session/data_msgp.go" -tests=true -unexported
|
||||||
|
go run github.com/tinylib/msgp@latest -file="middleware/csrf/storage_manager.go" -o="middleware/csrf/storage_manager_msgp.go" -tests=true -unexported
|
||||||
|
go run github.com/tinylib/msgp@latest -file="middleware/limiter/manager.go" -o="middleware/limiter/manager_msgp.go" -tests=true -unexported
|
||||||
|
go run github.com/tinylib/msgp@latest -file="middleware/idempotency/response.go" -o="middleware/idempotency/response_msgp.go" -tests=true -unexported
|
||||||
|
|
|
@ -40,6 +40,10 @@ func (b *formBinding) Bind(reqCtx *fasthttp.RequestCtx, out any) error {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
return parse(b.Name(), out, data)
|
return parse(b.Name(), out, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -674,7 +674,7 @@ func setConfigToRequest(req *Request, config ...Config) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if cfg.File != nil && len(cfg.File) != 0 {
|
if len(cfg.File) != 0 {
|
||||||
req.AddFiles(cfg.File...)
|
req.AddFiles(cfg.File...)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -1422,7 +1422,7 @@ func Test_Set_Config_To_Request(t *testing.T) {
|
||||||
key := struct{}{}
|
key := struct{}{}
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
ctx = context.WithValue(ctx, key, "v1")
|
ctx = context.WithValue(ctx, key, "v1") //nolint: staticcheck // not needed for tests
|
||||||
|
|
||||||
req := AcquireRequest()
|
req := AcquireRequest()
|
||||||
|
|
||||||
|
|
|
@ -84,7 +84,7 @@ func Test_Request_Context(t *testing.T) {
|
||||||
|
|
||||||
require.Nil(t, ctx.Value(key))
|
require.Nil(t, ctx.Value(key))
|
||||||
|
|
||||||
ctx = context.WithValue(ctx, key, "string")
|
ctx = context.WithValue(ctx, key, "string") //nolint: staticcheck // not needed for tests
|
||||||
req.SetContext(ctx)
|
req.SetContext(ctx)
|
||||||
ctx = req.Context()
|
ctx = req.Context()
|
||||||
|
|
||||||
|
@ -1603,8 +1603,8 @@ func Benchmark_SetValWithStruct(b *testing.B) {
|
||||||
require.Empty(b, string(p.Peek("TInt")))
|
require.Empty(b, string(p.Peek("TInt")))
|
||||||
require.Empty(b, string(p.Peek("TString")))
|
require.Empty(b, string(p.Peek("TString")))
|
||||||
require.Empty(b, string(p.Peek("TFloat")))
|
require.Empty(b, string(p.Peek("TFloat")))
|
||||||
require.Empty(b, len(p.PeekMulti("TSlice")))
|
require.Empty(b, p.PeekMulti("TSlice"))
|
||||||
require.Empty(b, len(p.PeekMulti("int_slice")))
|
require.Empty(b, p.PeekMulti("int_slice"))
|
||||||
})
|
})
|
||||||
|
|
||||||
b.Run("error type should ignore", func(b *testing.B) {
|
b.Run("error type should ignore", func(b *testing.B) {
|
||||||
|
|
|
@ -8,7 +8,6 @@ import (
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/gofiber/utils/v2"
|
"github.com/gofiber/utils/v2"
|
||||||
|
@ -68,7 +67,7 @@ func (r *Response) Body() []byte {
|
||||||
|
|
||||||
// String method returns the body of the server response as String.
|
// String method returns the body of the server response as String.
|
||||||
func (r *Response) String() string {
|
func (r *Response) String() string {
|
||||||
return strings.TrimSpace(string(r.Body()))
|
return utils.Trim(string(r.Body()), ' ')
|
||||||
}
|
}
|
||||||
|
|
||||||
// JSON method will unmarshal body to json.
|
// JSON method will unmarshal body to json.
|
||||||
|
|
39
ctx.go
39
ctx.go
|
@ -273,10 +273,7 @@ func (c *DefaultCtx) BaseURL() string {
|
||||||
// Returned value is only valid within the handler. Do not store any references.
|
// Returned value is only valid within the handler. Do not store any references.
|
||||||
// Make copies or use the Immutable setting instead.
|
// Make copies or use the Immutable setting instead.
|
||||||
func (c *DefaultCtx) BodyRaw() []byte {
|
func (c *DefaultCtx) BodyRaw() []byte {
|
||||||
if c.app.config.Immutable {
|
return c.getBody()
|
||||||
return utils.CopyBytes(c.fasthttp.Request.Body())
|
|
||||||
}
|
|
||||||
return c.fasthttp.Request.Body()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *DefaultCtx) tryDecodeBodyInOrder(
|
func (c *DefaultCtx) tryDecodeBodyInOrder(
|
||||||
|
@ -339,21 +336,19 @@ func (c *DefaultCtx) Body() []byte {
|
||||||
encodingOrder = []string{"", "", ""}
|
encodingOrder = []string{"", "", ""}
|
||||||
)
|
)
|
||||||
|
|
||||||
// faster than peek
|
// Get Content-Encoding header
|
||||||
c.Request().Header.VisitAll(func(key, value []byte) {
|
headerEncoding = utils.UnsafeString(c.Request().Header.ContentEncoding())
|
||||||
if c.app.getString(key) == HeaderContentEncoding {
|
|
||||||
headerEncoding = c.app.getString(value)
|
// If no encoding is provided, return the original body
|
||||||
|
if len(headerEncoding) == 0 {
|
||||||
|
return c.getBody()
|
||||||
}
|
}
|
||||||
})
|
|
||||||
|
|
||||||
// Split and get the encodings list, in order to attend the
|
// Split and get the encodings list, in order to attend the
|
||||||
// rule defined at: https://www.rfc-editor.org/rfc/rfc9110#section-8.4-5
|
// rule defined at: https://www.rfc-editor.org/rfc/rfc9110#section-8.4-5
|
||||||
encodingOrder = getSplicedStrList(headerEncoding, encodingOrder)
|
encodingOrder = getSplicedStrList(headerEncoding, encodingOrder)
|
||||||
if len(encodingOrder) == 0 {
|
if len(encodingOrder) == 0 {
|
||||||
if c.app.config.Immutable {
|
return c.getBody()
|
||||||
return utils.CopyBytes(c.fasthttp.Request.Body())
|
|
||||||
}
|
|
||||||
return c.fasthttp.Request.Body()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var decodesRealized uint8
|
var decodesRealized uint8
|
||||||
|
@ -778,7 +773,7 @@ iploop:
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
|
|
||||||
s := strings.TrimRight(headerValue[i:j], " ")
|
s := utils.TrimRight(headerValue[i:j], ' ')
|
||||||
|
|
||||||
if c.app.config.EnableIPValidation {
|
if c.app.config.EnableIPValidation {
|
||||||
// Skip validation if IP is clearly not IPv4/IPv6, otherwise validate without allocations
|
// Skip validation if IP is clearly not IPv4/IPv6, otherwise validate without allocations
|
||||||
|
@ -828,7 +823,7 @@ func (c *DefaultCtx) extractIPFromHeader(header string) string {
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
|
|
||||||
s := strings.TrimRight(headerValue[i:j], " ")
|
s := utils.TrimRight(headerValue[i:j], ' ')
|
||||||
|
|
||||||
if c.app.config.EnableIPValidation {
|
if c.app.config.EnableIPValidation {
|
||||||
if (!v6 && !v4) || (v6 && !utils.IsIPv6(s)) || (v4 && !utils.IsIPv4(s)) {
|
if (!v6 && !v4) || (v6 && !utils.IsIPv6(s)) || (v4 && !utils.IsIPv4(s)) {
|
||||||
|
@ -862,7 +857,7 @@ func (c *DefaultCtx) Is(extension string) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
return strings.HasPrefix(
|
return strings.HasPrefix(
|
||||||
strings.TrimLeft(utils.UnsafeString(c.fasthttp.Request.Header.ContentType()), " "),
|
utils.TrimLeft(utils.UnsafeString(c.fasthttp.Request.Header.ContentType()), ' '),
|
||||||
extensionHeader,
|
extensionHeader,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -939,7 +934,7 @@ func (c *DefaultCtx) Links(link ...string) {
|
||||||
bb.WriteString(`; rel="` + link[i] + `",`)
|
bb.WriteString(`; rel="` + link[i] + `",`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
c.setCanonical(HeaderLink, strings.TrimRight(c.app.getString(bb.Bytes()), ","))
|
c.setCanonical(HeaderLink, utils.TrimRight(c.app.getString(bb.Bytes()), ','))
|
||||||
bytebufferpool.Put(bb)
|
bytebufferpool.Put(bb)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1810,7 +1805,7 @@ func (c *DefaultCtx) configDependentPaths() {
|
||||||
}
|
}
|
||||||
// If StrictRouting is disabled, we strip all trailing slashes
|
// If StrictRouting is disabled, we strip all trailing slashes
|
||||||
if !c.app.config.StrictRouting && len(c.detectionPathBuffer) > 1 && c.detectionPathBuffer[len(c.detectionPathBuffer)-1] == '/' {
|
if !c.app.config.StrictRouting && len(c.detectionPathBuffer) > 1 && c.detectionPathBuffer[len(c.detectionPathBuffer)-1] == '/' {
|
||||||
c.detectionPathBuffer = bytes.TrimRight(c.detectionPathBuffer, "/")
|
c.detectionPathBuffer = utils.TrimRight(c.detectionPathBuffer, '/')
|
||||||
}
|
}
|
||||||
c.detectionPath = c.app.getString(c.detectionPathBuffer)
|
c.detectionPath = c.app.getString(c.detectionPathBuffer)
|
||||||
|
|
||||||
|
@ -1909,6 +1904,14 @@ func (c *DefaultCtx) release() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *DefaultCtx) getBody() []byte {
|
||||||
|
if c.app.config.Immutable {
|
||||||
|
return utils.CopyBytes(c.fasthttp.Request.Body())
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.fasthttp.Request.Body()
|
||||||
|
}
|
||||||
|
|
||||||
// Methods to use with next stack.
|
// Methods to use with next stack.
|
||||||
func (c *DefaultCtx) getMethodINT() int {
|
func (c *DefaultCtx) getMethodINT() int {
|
||||||
return c.methodINT
|
return c.methodINT
|
||||||
|
|
60
ctx_test.go
60
ctx_test.go
|
@ -356,6 +356,26 @@ func Test_Ctx_Body(t *testing.T) {
|
||||||
require.Equal(t, []byte("john=doe"), c.Body())
|
require.Equal(t, []byte("john=doe"), c.Body())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// go test -run Test_Ctx_BodyRaw
|
||||||
|
func Test_Ctx_BodyRaw(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
app := New()
|
||||||
|
c := app.AcquireCtx(&fasthttp.RequestCtx{}).(*DefaultCtx) //nolint:errcheck, forcetypeassert // not needed
|
||||||
|
|
||||||
|
c.Request().SetBodyRaw([]byte("john=doe"))
|
||||||
|
require.Equal(t, []byte("john=doe"), c.BodyRaw())
|
||||||
|
}
|
||||||
|
|
||||||
|
// go test -run Test_Ctx_BodyRaw_Immutable
|
||||||
|
func Test_Ctx_BodyRaw_Immutable(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
app := New(Config{Immutable: true})
|
||||||
|
c := app.AcquireCtx(&fasthttp.RequestCtx{}).(*DefaultCtx) //nolint:errcheck, forcetypeassert // not needed
|
||||||
|
|
||||||
|
c.Request().SetBodyRaw([]byte("john=doe"))
|
||||||
|
require.Equal(t, []byte("john=doe"), c.BodyRaw())
|
||||||
|
}
|
||||||
|
|
||||||
// go test -v -run=^$ -bench=Benchmark_Ctx_Body -benchmem -count=4
|
// go test -v -run=^$ -bench=Benchmark_Ctx_Body -benchmem -count=4
|
||||||
func Benchmark_Ctx_Body(b *testing.B) {
|
func Benchmark_Ctx_Body(b *testing.B) {
|
||||||
const input = "john=doe"
|
const input = "john=doe"
|
||||||
|
@ -373,6 +393,40 @@ func Benchmark_Ctx_Body(b *testing.B) {
|
||||||
require.Equal(b, []byte(input), c.Body())
|
require.Equal(b, []byte(input), c.Body())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// go test -v -run=^$ -bench=Benchmark_Ctx_BodyRaw -benchmem -count=4
|
||||||
|
func Benchmark_Ctx_BodyRaw(b *testing.B) {
|
||||||
|
const input = "john=doe"
|
||||||
|
|
||||||
|
app := New()
|
||||||
|
c := app.AcquireCtx(&fasthttp.RequestCtx{}).(*DefaultCtx) //nolint:errcheck, forcetypeassert // not needed
|
||||||
|
|
||||||
|
c.Request().SetBodyRaw([]byte(input))
|
||||||
|
b.ReportAllocs()
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
_ = c.BodyRaw()
|
||||||
|
}
|
||||||
|
|
||||||
|
require.Equal(b, []byte(input), c.BodyRaw())
|
||||||
|
}
|
||||||
|
|
||||||
|
// go test -v -run=^$ -bench=Benchmark_Ctx_BodyRaw_Immutable -benchmem -count=4
|
||||||
|
func Benchmark_Ctx_BodyRaw_Immutable(b *testing.B) {
|
||||||
|
const input = "john=doe"
|
||||||
|
|
||||||
|
app := New(Config{Immutable: true})
|
||||||
|
c := app.AcquireCtx(&fasthttp.RequestCtx{}).(*DefaultCtx) //nolint:errcheck, forcetypeassert // not needed
|
||||||
|
|
||||||
|
c.Request().SetBodyRaw([]byte(input))
|
||||||
|
b.ReportAllocs()
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
_ = c.BodyRaw()
|
||||||
|
}
|
||||||
|
|
||||||
|
require.Equal(b, []byte(input), c.BodyRaw())
|
||||||
|
}
|
||||||
|
|
||||||
// go test -run Test_Ctx_Body_Immutable
|
// go test -run Test_Ctx_Body_Immutable
|
||||||
func Test_Ctx_Body_Immutable(t *testing.T) {
|
func Test_Ctx_Body_Immutable(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
@ -813,7 +867,7 @@ func Test_Ctx_UserContext(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
testKey := struct{}{}
|
testKey := struct{}{}
|
||||||
testValue := "Test Value"
|
testValue := "Test Value"
|
||||||
ctx := context.WithValue(context.Background(), testKey, testValue)
|
ctx := context.WithValue(context.Background(), testKey, testValue) //nolint: staticcheck // not needed for tests
|
||||||
require.Equal(t, testValue, ctx.Value(testKey))
|
require.Equal(t, testValue, ctx.Value(testKey))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -826,7 +880,7 @@ func Test_Ctx_SetUserContext(t *testing.T) {
|
||||||
|
|
||||||
testKey := struct{}{}
|
testKey := struct{}{}
|
||||||
testValue := "Test Value"
|
testValue := "Test Value"
|
||||||
ctx := context.WithValue(context.Background(), testKey, testValue)
|
ctx := context.WithValue(context.Background(), testKey, testValue) //nolint: staticcheck // not needed for tests
|
||||||
c.SetUserContext(ctx)
|
c.SetUserContext(ctx)
|
||||||
require.Equal(t, testValue, c.UserContext().Value(testKey))
|
require.Equal(t, testValue, c.UserContext().Value(testKey))
|
||||||
}
|
}
|
||||||
|
@ -846,7 +900,7 @@ func Test_Ctx_UserContext_Multiple_Requests(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
input := utils.CopyString(Query(c, "input", "NO_VALUE"))
|
input := utils.CopyString(Query(c, "input", "NO_VALUE"))
|
||||||
ctx = context.WithValue(ctx, testKey, fmt.Sprintf("%s_%s", testValue, input))
|
ctx = context.WithValue(ctx, testKey, fmt.Sprintf("%s_%s", testValue, input)) //nolint: staticcheck // not needed for tests
|
||||||
c.SetUserContext(ctx)
|
c.SetUserContext(ctx)
|
||||||
|
|
||||||
return c.Status(StatusOK).SendString(fmt.Sprintf("resp_%s_returned", input))
|
return c.Status(StatusOK).SendString(fmt.Sprintf("resp_%s_returned", input))
|
||||||
|
|
|
@ -32,7 +32,7 @@ app.Use(func(c fiber.Ctx) error {
|
||||||
|
|
||||||
## How can i use live reload ?
|
## How can i use live reload ?
|
||||||
|
|
||||||
[Air](https://github.com/cosmtrek/air) is a handy tool that automatically restarts your Go applications whenever the source code changes, making your development process faster and more efficient.
|
[Air](https://github.com/air-verse/air) is a handy tool that automatically restarts your Go applications whenever the source code changes, making your development process faster and more efficient.
|
||||||
|
|
||||||
To use Air in a Fiber project, follow these steps:
|
To use Air in a Fiber project, follow these steps:
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ These docs are for **Fiber v3**, which was released on **March XX, 2024**.
|
||||||
|
|
||||||
### Installation
|
### Installation
|
||||||
|
|
||||||
First of all, [download](https://go.dev/dl/) and install Go. `1.21` or higher is required.
|
First of all, [download](https://go.dev/dl/) and install Go. `1.22` or higher is required.
|
||||||
|
|
||||||
Installation is done using the [`go get`](https://pkg.go.dev/cmd/go/#hdr-Add_dependencies_to_current_module_and_install_them) command:
|
Installation is done using the [`go get`](https://pkg.go.dev/cmd/go/#hdr-Add_dependencies_to_current_module_and_install_them) command:
|
||||||
|
|
||||||
|
|
|
@ -38,7 +38,7 @@ Here's a quick overview of the changes in Fiber `v3`:
|
||||||
|
|
||||||
## Drop for old Go versions
|
## Drop for old Go versions
|
||||||
|
|
||||||
Fiber `v3` drops support for Go versions below `1.21`. We recommend upgrading to Go `1.21` or higher to use Fiber `v3`.
|
Fiber `v3` drops support for Go versions below `1.22`. We recommend upgrading to Go `1.22` or higher to use Fiber `v3`.
|
||||||
|
|
||||||
## 🚀 App
|
## 🚀 App
|
||||||
|
|
||||||
|
|
4
go.mod
4
go.mod
|
@ -1,9 +1,9 @@
|
||||||
module github.com/gofiber/fiber/v3
|
module github.com/gofiber/fiber/v3
|
||||||
|
|
||||||
go 1.21
|
go 1.22
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/gofiber/utils/v2 v2.0.0-beta.5
|
github.com/gofiber/utils/v2 v2.0.0-beta.6
|
||||||
github.com/google/uuid v1.6.0
|
github.com/google/uuid v1.6.0
|
||||||
github.com/mattn/go-colorable v0.1.13
|
github.com/mattn/go-colorable v0.1.13
|
||||||
github.com/mattn/go-isatty v0.0.20
|
github.com/mattn/go-isatty v0.0.20
|
||||||
|
|
4
go.sum
4
go.sum
|
@ -2,8 +2,8 @@ github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1
|
||||||
github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
|
github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/gofiber/utils/v2 v2.0.0-beta.5 h1:zbDIU8gVAlZ2Ak9Fk8APlis4S7wUiQFbcvv6UASkm6A=
|
github.com/gofiber/utils/v2 v2.0.0-beta.6 h1:ED62bOmpRXdgviPlfTmf0Q+AXzhaTUAFtdWjgx+XkYI=
|
||||||
github.com/gofiber/utils/v2 v2.0.0-beta.5/go.mod h1:3Kz8Px3jInKFvqxDzDeoSygwEOO+3uyubTmUa6PqY+0=
|
github.com/gofiber/utils/v2 v2.0.0-beta.6/go.mod h1:3Kz8Px3jInKFvqxDzDeoSygwEOO+3uyubTmUa6PqY+0=
|
||||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
|
github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
|
||||||
|
|
|
@ -222,7 +222,7 @@ func getGroupPath(prefix, path string) string {
|
||||||
path = "/" + path
|
path = "/" + path
|
||||||
}
|
}
|
||||||
|
|
||||||
return strings.TrimRight(prefix, "/") + path
|
return utils.TrimRight(prefix, '/') + path
|
||||||
}
|
}
|
||||||
|
|
||||||
// acceptsOffer This function determines if an offer matches a given specification.
|
// acceptsOffer This function determines if an offer matches a given specification.
|
||||||
|
@ -336,7 +336,7 @@ func getSplicedStrList(headerValue string, dst []string) []string {
|
||||||
dst = make([]string, len(dst)+(len(dst)>>1)+2)
|
dst = make([]string, len(dst)+(len(dst)>>1)+2)
|
||||||
copy(dst, oldSlice)
|
copy(dst, oldSlice)
|
||||||
}
|
}
|
||||||
dst[insertIndex] = strings.TrimLeft(headerValue[lastElementEndsAt:index], " ")
|
dst[insertIndex] = utils.TrimLeft(headerValue[lastElementEndsAt:index], ' ')
|
||||||
lastElementEndsAt = uint8(index + 1)
|
lastElementEndsAt = uint8(index + 1)
|
||||||
insertIndex++
|
insertIndex++
|
||||||
}
|
}
|
||||||
|
@ -356,7 +356,7 @@ func forEachMediaRange(header []byte, functor func([]byte)) {
|
||||||
|
|
||||||
for len(header) > 0 {
|
for len(header) > 0 {
|
||||||
n := 0
|
n := 0
|
||||||
header = bytes.TrimLeft(header, " ")
|
header = utils.TrimLeft(header, ' ')
|
||||||
quotes := 0
|
quotes := 0
|
||||||
escaping := false
|
escaping := false
|
||||||
|
|
||||||
|
@ -459,7 +459,7 @@ func getOffer(header []byte, isAccepted func(spec, offer string, specParams head
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
spec = bytes.TrimSpace(spec)
|
spec = utils.Trim(spec, ' ')
|
||||||
|
|
||||||
// Determine specificity
|
// Determine specificity
|
||||||
var specificity int
|
var specificity int
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
package fiber
|
package fiber
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
@ -533,8 +532,7 @@ func Test_Utils_IsNoCache(t *testing.T) {
|
||||||
|
|
||||||
for _, c := range testCases {
|
for _, c := range testCases {
|
||||||
ok := isNoCache(c.string)
|
ok := isNoCache(c.string)
|
||||||
require.Equal(t, c.bool, ok,
|
require.Equal(t, c.bool, ok, "want %t, got isNoCache(%s)=%t", c.bool, c.string, ok)
|
||||||
fmt.Sprintf("want %t, got isNoCache(%s)=%t", c.bool, c.string, ok))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -351,7 +351,7 @@ func (app *App) startupMessage(addr string, isTLS bool, pids string, cfg ListenC
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Fprintf(out, "%s\n", fmt.Sprintf(figletFiberText, colors.Red+"v"+Version+colors.Reset)) //nolint:errcheck,revive // ignore error
|
fmt.Fprintf(out, "%s\n", fmt.Sprintf(figletFiberText, colors.Red+"v"+Version+colors.Reset)) //nolint:errcheck,revive // ignore error
|
||||||
fmt.Fprintf(out, strings.Repeat("-", 50)+"\n") //nolint:errcheck,revive // ignore error
|
fmt.Fprintf(out, strings.Repeat("-", 50)+"\n") //nolint:errcheck,revive,govet // ignore error
|
||||||
|
|
||||||
if host == "0.0.0.0" {
|
if host == "0.0.0.0" {
|
||||||
//nolint:errcheck,revive // ignore error
|
//nolint:errcheck,revive // ignore error
|
||||||
|
|
|
@ -880,7 +880,7 @@ func Test_Cache_MaxBytesOrder(t *testing.T) {
|
||||||
for idx, tcase := range cases {
|
for idx, tcase := range cases {
|
||||||
rsp, err := app.Test(httptest.NewRequest(fiber.MethodGet, tcase[0], nil))
|
rsp, err := app.Test(httptest.NewRequest(fiber.MethodGet, tcase[0], nil))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, tcase[1], rsp.Header.Get("X-Cache"), fmt.Sprintf("Case %v", idx))
|
require.Equal(t, tcase[1], rsp.Header.Get("X-Cache"), "Case %v", idx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -914,7 +914,7 @@ func Test_Cache_MaxBytesSizes(t *testing.T) {
|
||||||
for idx, tcase := range cases {
|
for idx, tcase := range cases {
|
||||||
rsp, err := app.Test(httptest.NewRequest(fiber.MethodGet, tcase[0], nil))
|
rsp, err := app.Test(httptest.NewRequest(fiber.MethodGet, tcase[0], nil))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, tcase[1], rsp.Header.Get("X-Cache"), fmt.Sprintf("Case %v", idx))
|
require.Equal(t, tcase[1], rsp.Header.Get("X-Cache"), "Case %v", idx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,8 +8,9 @@ import (
|
||||||
"github.com/gofiber/fiber/v3/internal/memory"
|
"github.com/gofiber/fiber/v3/internal/memory"
|
||||||
)
|
)
|
||||||
|
|
||||||
// go:generate msgp
|
// msgp -file="manager.go" -o="manager_msgp.go" -tests=true -unexported
|
||||||
// msgp -file="manager.go" -o="manager_msgp.go" -tests=false -unexported
|
//
|
||||||
|
//go:generate msgp
|
||||||
type item struct {
|
type item struct {
|
||||||
headers map[string][]byte
|
headers map[string][]byte
|
||||||
body []byte
|
body []byte
|
||||||
|
|
|
@ -6,12 +6,202 @@ import (
|
||||||
"github.com/tinylib/msgp/msgp"
|
"github.com/tinylib/msgp/msgp"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// DecodeMsg implements msgp.Decodable
|
||||||
|
func (z *item) DecodeMsg(dc *msgp.Reader) (err error) {
|
||||||
|
var field []byte
|
||||||
|
_ = field
|
||||||
|
var zb0001 uint32
|
||||||
|
zb0001, err = dc.ReadMapHeader()
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for zb0001 > 0 {
|
||||||
|
zb0001--
|
||||||
|
field, err = dc.ReadMapKeyPtr()
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch msgp.UnsafeString(field) {
|
||||||
|
case "headers":
|
||||||
|
var zb0002 uint32
|
||||||
|
zb0002, err = dc.ReadMapHeader()
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err, "headers")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if z.headers == nil {
|
||||||
|
z.headers = make(map[string][]byte, zb0002)
|
||||||
|
} else if len(z.headers) > 0 {
|
||||||
|
for key := range z.headers {
|
||||||
|
delete(z.headers, key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for zb0002 > 0 {
|
||||||
|
zb0002--
|
||||||
|
var za0001 string
|
||||||
|
var za0002 []byte
|
||||||
|
za0001, err = dc.ReadString()
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err, "headers")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
za0002, err = dc.ReadBytes(za0002)
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err, "headers", za0001)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
z.headers[za0001] = za0002
|
||||||
|
}
|
||||||
|
case "body":
|
||||||
|
z.body, err = dc.ReadBytes(z.body)
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err, "body")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
case "ctype":
|
||||||
|
z.ctype, err = dc.ReadBytes(z.ctype)
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err, "ctype")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
case "cencoding":
|
||||||
|
z.cencoding, err = dc.ReadBytes(z.cencoding)
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err, "cencoding")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
case "status":
|
||||||
|
z.status, err = dc.ReadInt()
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err, "status")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
case "exp":
|
||||||
|
z.exp, err = dc.ReadUint64()
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err, "exp")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
case "heapidx":
|
||||||
|
z.heapidx, err = dc.ReadInt()
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err, "heapidx")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
err = dc.Skip()
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// EncodeMsg implements msgp.Encodable
|
||||||
|
func (z *item) EncodeMsg(en *msgp.Writer) (err error) {
|
||||||
|
// map header, size 7
|
||||||
|
// write "headers"
|
||||||
|
err = en.Append(0x87, 0xa7, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = en.WriteMapHeader(uint32(len(z.headers)))
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err, "headers")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for za0001, za0002 := range z.headers {
|
||||||
|
err = en.WriteString(za0001)
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err, "headers")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = en.WriteBytes(za0002)
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err, "headers", za0001)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// write "body"
|
||||||
|
err = en.Append(0xa4, 0x62, 0x6f, 0x64, 0x79)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = en.WriteBytes(z.body)
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err, "body")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// write "ctype"
|
||||||
|
err = en.Append(0xa5, 0x63, 0x74, 0x79, 0x70, 0x65)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = en.WriteBytes(z.ctype)
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err, "ctype")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// write "cencoding"
|
||||||
|
err = en.Append(0xa9, 0x63, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = en.WriteBytes(z.cencoding)
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err, "cencoding")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// write "status"
|
||||||
|
err = en.Append(0xa6, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = en.WriteInt(z.status)
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err, "status")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// write "exp"
|
||||||
|
err = en.Append(0xa3, 0x65, 0x78, 0x70)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = en.WriteUint64(z.exp)
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err, "exp")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// write "heapidx"
|
||||||
|
err = en.Append(0xa7, 0x68, 0x65, 0x61, 0x70, 0x69, 0x64, 0x78)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = en.WriteInt(z.heapidx)
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err, "heapidx")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// MarshalMsg implements msgp.Marshaler
|
// MarshalMsg implements msgp.Marshaler
|
||||||
func (z *item) MarshalMsg(b []byte) (o []byte, err error) {
|
func (z *item) MarshalMsg(b []byte) (o []byte, err error) {
|
||||||
o = msgp.Require(b, z.Msgsize())
|
o = msgp.Require(b, z.Msgsize())
|
||||||
// map header, size 7
|
// map header, size 7
|
||||||
|
// string "headers"
|
||||||
|
o = append(o, 0x87, 0xa7, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73)
|
||||||
|
o = msgp.AppendMapHeader(o, uint32(len(z.headers)))
|
||||||
|
for za0001, za0002 := range z.headers {
|
||||||
|
o = msgp.AppendString(o, za0001)
|
||||||
|
o = msgp.AppendBytes(o, za0002)
|
||||||
|
}
|
||||||
// string "body"
|
// string "body"
|
||||||
o = append(o, 0x87, 0xa4, 0x62, 0x6f, 0x64, 0x79)
|
o = append(o, 0xa4, 0x62, 0x6f, 0x64, 0x79)
|
||||||
o = msgp.AppendBytes(o, z.body)
|
o = msgp.AppendBytes(o, z.body)
|
||||||
// string "ctype"
|
// string "ctype"
|
||||||
o = append(o, 0xa5, 0x63, 0x74, 0x79, 0x70, 0x65)
|
o = append(o, 0xa5, 0x63, 0x74, 0x79, 0x70, 0x65)
|
||||||
|
@ -25,13 +215,6 @@ func (z *item) MarshalMsg(b []byte) (o []byte, err error) {
|
||||||
// string "exp"
|
// string "exp"
|
||||||
o = append(o, 0xa3, 0x65, 0x78, 0x70)
|
o = append(o, 0xa3, 0x65, 0x78, 0x70)
|
||||||
o = msgp.AppendUint64(o, z.exp)
|
o = msgp.AppendUint64(o, z.exp)
|
||||||
// string "headers"
|
|
||||||
o = append(o, 0xa7, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73)
|
|
||||||
o = msgp.AppendMapHeader(o, uint32(len(z.headers)))
|
|
||||||
for za0001, za0002 := range z.headers {
|
|
||||||
o = msgp.AppendString(o, za0001)
|
|
||||||
o = msgp.AppendBytes(o, za0002)
|
|
||||||
}
|
|
||||||
// string "heapidx"
|
// string "heapidx"
|
||||||
o = append(o, 0xa7, 0x68, 0x65, 0x61, 0x70, 0x69, 0x64, 0x78)
|
o = append(o, 0xa7, 0x68, 0x65, 0x61, 0x70, 0x69, 0x64, 0x78)
|
||||||
o = msgp.AppendInt(o, z.heapidx)
|
o = msgp.AppendInt(o, z.heapidx)
|
||||||
|
@ -56,36 +239,6 @@ func (z *item) UnmarshalMsg(bts []byte) (o []byte, err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
switch msgp.UnsafeString(field) {
|
switch msgp.UnsafeString(field) {
|
||||||
case "body":
|
|
||||||
z.body, bts, err = msgp.ReadBytesBytes(bts, z.body)
|
|
||||||
if err != nil {
|
|
||||||
err = msgp.WrapError(err, "body")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
case "ctype":
|
|
||||||
z.ctype, bts, err = msgp.ReadBytesBytes(bts, z.ctype)
|
|
||||||
if err != nil {
|
|
||||||
err = msgp.WrapError(err, "ctype")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
case "cencoding":
|
|
||||||
z.cencoding, bts, err = msgp.ReadBytesBytes(bts, z.cencoding)
|
|
||||||
if err != nil {
|
|
||||||
err = msgp.WrapError(err, "cencoding")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
case "status":
|
|
||||||
z.status, bts, err = msgp.ReadIntBytes(bts)
|
|
||||||
if err != nil {
|
|
||||||
err = msgp.WrapError(err, "status")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
case "exp":
|
|
||||||
z.exp, bts, err = msgp.ReadUint64Bytes(bts)
|
|
||||||
if err != nil {
|
|
||||||
err = msgp.WrapError(err, "exp")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
case "headers":
|
case "headers":
|
||||||
var zb0002 uint32
|
var zb0002 uint32
|
||||||
zb0002, bts, err = msgp.ReadMapHeaderBytes(bts)
|
zb0002, bts, err = msgp.ReadMapHeaderBytes(bts)
|
||||||
|
@ -116,6 +269,36 @@ func (z *item) UnmarshalMsg(bts []byte) (o []byte, err error) {
|
||||||
}
|
}
|
||||||
z.headers[za0001] = za0002
|
z.headers[za0001] = za0002
|
||||||
}
|
}
|
||||||
|
case "body":
|
||||||
|
z.body, bts, err = msgp.ReadBytesBytes(bts, z.body)
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err, "body")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
case "ctype":
|
||||||
|
z.ctype, bts, err = msgp.ReadBytesBytes(bts, z.ctype)
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err, "ctype")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
case "cencoding":
|
||||||
|
z.cencoding, bts, err = msgp.ReadBytesBytes(bts, z.cencoding)
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err, "cencoding")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
case "status":
|
||||||
|
z.status, bts, err = msgp.ReadIntBytes(bts)
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err, "status")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
case "exp":
|
||||||
|
z.exp, bts, err = msgp.ReadUint64Bytes(bts)
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err, "exp")
|
||||||
|
return
|
||||||
|
}
|
||||||
case "heapidx":
|
case "heapidx":
|
||||||
z.heapidx, bts, err = msgp.ReadIntBytes(bts)
|
z.heapidx, bts, err = msgp.ReadIntBytes(bts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -136,13 +319,13 @@ func (z *item) UnmarshalMsg(bts []byte) (o []byte, err error) {
|
||||||
|
|
||||||
// Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message
|
// Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message
|
||||||
func (z *item) Msgsize() (s int) {
|
func (z *item) Msgsize() (s int) {
|
||||||
s = 1 + 5 + msgp.BytesPrefixSize + len(z.body) + 6 + msgp.BytesPrefixSize + len(z.ctype) + 10 + msgp.BytesPrefixSize + len(z.cencoding) + 7 + msgp.IntSize + 4 + msgp.Uint64Size + 8 + msgp.MapHeaderSize
|
s = 1 + 8 + msgp.MapHeaderSize
|
||||||
if z.headers != nil {
|
if z.headers != nil {
|
||||||
for za0001, za0002 := range z.headers {
|
for za0001, za0002 := range z.headers {
|
||||||
_ = za0002
|
_ = za0002
|
||||||
s += msgp.StringPrefixSize + len(za0001) + msgp.BytesPrefixSize + len(za0002)
|
s += msgp.StringPrefixSize + len(za0001) + msgp.BytesPrefixSize + len(za0002)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
s += 8 + msgp.IntSize
|
s += 5 + msgp.BytesPrefixSize + len(z.body) + 6 + msgp.BytesPrefixSize + len(z.ctype) + 10 + msgp.BytesPrefixSize + len(z.cencoding) + 7 + msgp.IntSize + 4 + msgp.Uint64Size + 8 + msgp.IntSize
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,12 +3,13 @@ package cache
|
||||||
// Code generated by github.com/tinylib/msgp DO NOT EDIT.
|
// Code generated by github.com/tinylib/msgp DO NOT EDIT.
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/tinylib/msgp/msgp"
|
"github.com/tinylib/msgp/msgp"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Test_MarshalUnmarshalitem(t *testing.T) {
|
func TestMarshalUnmarshalitem(t *testing.T) {
|
||||||
v := item{}
|
v := item{}
|
||||||
bts, err := v.MarshalMsg(nil)
|
bts, err := v.MarshalMsg(nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -31,7 +32,7 @@ func Test_MarshalUnmarshalitem(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func Benchmark_MarshalMsgitem(b *testing.B) {
|
func BenchmarkMarshalMsgitem(b *testing.B) {
|
||||||
v := item{}
|
v := item{}
|
||||||
b.ReportAllocs()
|
b.ReportAllocs()
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
|
@ -40,7 +41,7 @@ func Benchmark_MarshalMsgitem(b *testing.B) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func Benchmark_AppendMsgitem(b *testing.B) {
|
func BenchmarkAppendMsgitem(b *testing.B) {
|
||||||
v := item{}
|
v := item{}
|
||||||
bts := make([]byte, 0, v.Msgsize())
|
bts := make([]byte, 0, v.Msgsize())
|
||||||
bts, _ = v.MarshalMsg(bts[0:0])
|
bts, _ = v.MarshalMsg(bts[0:0])
|
||||||
|
@ -52,7 +53,7 @@ func Benchmark_AppendMsgitem(b *testing.B) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func Benchmark_Unmarshalitem(b *testing.B) {
|
func BenchmarkUnmarshalitem(b *testing.B) {
|
||||||
v := item{}
|
v := item{}
|
||||||
bts, _ := v.MarshalMsg(nil)
|
bts, _ := v.MarshalMsg(nil)
|
||||||
b.ReportAllocs()
|
b.ReportAllocs()
|
||||||
|
@ -65,3 +66,58 @@ func Benchmark_Unmarshalitem(b *testing.B) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestEncodeDecodeitem(t *testing.T) {
|
||||||
|
v := item{}
|
||||||
|
var buf bytes.Buffer
|
||||||
|
msgp.Encode(&buf, &v)
|
||||||
|
|
||||||
|
m := v.Msgsize()
|
||||||
|
if buf.Len() > m {
|
||||||
|
t.Log("WARNING: TestEncodeDecodeitem Msgsize() is inaccurate")
|
||||||
|
}
|
||||||
|
|
||||||
|
vn := item{}
|
||||||
|
err := msgp.Decode(&buf, &vn)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
buf.Reset()
|
||||||
|
msgp.Encode(&buf, &v)
|
||||||
|
err = msgp.NewReader(&buf).Skip()
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkEncodeitem(b *testing.B) {
|
||||||
|
v := item{}
|
||||||
|
var buf bytes.Buffer
|
||||||
|
msgp.Encode(&buf, &v)
|
||||||
|
b.SetBytes(int64(buf.Len()))
|
||||||
|
en := msgp.NewWriter(msgp.Nowhere)
|
||||||
|
b.ReportAllocs()
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
v.EncodeMsg(en)
|
||||||
|
}
|
||||||
|
en.Flush()
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkDecodeitem(b *testing.B) {
|
||||||
|
v := item{}
|
||||||
|
var buf bytes.Buffer
|
||||||
|
msgp.Encode(&buf, &v)
|
||||||
|
b.SetBytes(int64(buf.Len()))
|
||||||
|
rd := msgp.NewEndlessReader(buf.Bytes(), b)
|
||||||
|
dc := msgp.NewReader(rd)
|
||||||
|
b.ReportAllocs()
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
err := v.DecodeMsg(dc)
|
||||||
|
if err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
|
|
||||||
"github.com/gofiber/fiber/v3"
|
"github.com/gofiber/fiber/v3"
|
||||||
"github.com/gofiber/fiber/v3/log"
|
"github.com/gofiber/fiber/v3/log"
|
||||||
|
"github.com/gofiber/utils/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
// New creates a new middleware handler
|
// New creates a new middleware handler
|
||||||
|
@ -44,7 +45,7 @@ func New(config ...Config) fiber.Handler {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if i := strings.Index(origin, "://*."); i != -1 {
|
if i := strings.Index(origin, "://*."); i != -1 {
|
||||||
trimmedOrigin := strings.TrimSpace(origin[:i+3] + origin[i+4:])
|
trimmedOrigin := utils.Trim(origin[:i+3]+origin[i+4:], ' ')
|
||||||
isValid, normalizedOrigin := normalizeOrigin(trimmedOrigin)
|
isValid, normalizedOrigin := normalizeOrigin(trimmedOrigin)
|
||||||
if !isValid {
|
if !isValid {
|
||||||
panic("[CORS] Invalid origin format in configuration: " + trimmedOrigin)
|
panic("[CORS] Invalid origin format in configuration: " + trimmedOrigin)
|
||||||
|
@ -52,7 +53,7 @@ func New(config ...Config) fiber.Handler {
|
||||||
sd := subdomain{prefix: normalizedOrigin[:i+3], suffix: normalizedOrigin[i+3:]}
|
sd := subdomain{prefix: normalizedOrigin[:i+3], suffix: normalizedOrigin[i+3:]}
|
||||||
allowSOrigins = append(allowSOrigins, sd)
|
allowSOrigins = append(allowSOrigins, sd)
|
||||||
} else {
|
} else {
|
||||||
trimmedOrigin := strings.TrimSpace(origin)
|
trimmedOrigin := utils.Trim(origin, ' ')
|
||||||
isValid, normalizedOrigin := normalizeOrigin(trimmedOrigin)
|
isValid, normalizedOrigin := normalizeOrigin(trimmedOrigin)
|
||||||
if !isValid {
|
if !isValid {
|
||||||
panic("[CORS] Invalid origin format in configuration: " + trimmedOrigin)
|
panic("[CORS] Invalid origin format in configuration: " + trimmedOrigin)
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gofiber/fiber/v3"
|
"github.com/gofiber/fiber/v3"
|
||||||
|
"github.com/gofiber/utils/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -62,7 +63,7 @@ func New(config ...Config) fiber.Handler {
|
||||||
|
|
||||||
for _, origin := range cfg.TrustedOrigins {
|
for _, origin := range cfg.TrustedOrigins {
|
||||||
if i := strings.Index(origin, "://*."); i != -1 {
|
if i := strings.Index(origin, "://*."); i != -1 {
|
||||||
trimmedOrigin := strings.TrimSpace(origin[:i+3] + origin[i+4:])
|
trimmedOrigin := utils.Trim(origin[:i+3]+origin[i+4:], ' ')
|
||||||
isValid, normalizedOrigin := normalizeOrigin(trimmedOrigin)
|
isValid, normalizedOrigin := normalizeOrigin(trimmedOrigin)
|
||||||
if !isValid {
|
if !isValid {
|
||||||
panic("[CSRF] Invalid origin format in configuration:" + origin)
|
panic("[CSRF] Invalid origin format in configuration:" + origin)
|
||||||
|
@ -70,7 +71,7 @@ func New(config ...Config) fiber.Handler {
|
||||||
sd := subdomain{prefix: normalizedOrigin[:i+3], suffix: normalizedOrigin[i+3:]}
|
sd := subdomain{prefix: normalizedOrigin[:i+3], suffix: normalizedOrigin[i+3:]}
|
||||||
trustedSubOrigins = append(trustedSubOrigins, sd)
|
trustedSubOrigins = append(trustedSubOrigins, sd)
|
||||||
} else {
|
} else {
|
||||||
trimmedOrigin := strings.TrimSpace(origin)
|
trimmedOrigin := utils.Trim(origin, ' ')
|
||||||
isValid, normalizedOrigin := normalizeOrigin(trimmedOrigin)
|
isValid, normalizedOrigin := normalizeOrigin(trimmedOrigin)
|
||||||
if !isValid {
|
if !isValid {
|
||||||
panic("[CSRF] Invalid origin format in configuration:" + origin)
|
panic("[CSRF] Invalid origin format in configuration:" + origin)
|
||||||
|
|
|
@ -139,7 +139,7 @@ func Test_CSRF_WithSession(t *testing.T) {
|
||||||
h(ctx)
|
h(ctx)
|
||||||
token := string(ctx.Response.Header.Peek(fiber.HeaderSetCookie))
|
token := string(ctx.Response.Header.Peek(fiber.HeaderSetCookie))
|
||||||
for _, header := range strings.Split(token, ";") {
|
for _, header := range strings.Split(token, ";") {
|
||||||
if strings.Split(strings.TrimSpace(header), "=")[0] == ConfigDefault.CookieName {
|
if strings.Split(utils.Trim(header, ' '), "=")[0] == ConfigDefault.CookieName {
|
||||||
token = strings.Split(header, "=")[1]
|
token = strings.Split(header, "=")[1]
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -248,7 +248,7 @@ func Test_CSRF_ExpiredToken_WithSession(t *testing.T) {
|
||||||
h(ctx)
|
h(ctx)
|
||||||
token := string(ctx.Response.Header.Peek(fiber.HeaderSetCookie))
|
token := string(ctx.Response.Header.Peek(fiber.HeaderSetCookie))
|
||||||
for _, header := range strings.Split(token, ";") {
|
for _, header := range strings.Split(token, ";") {
|
||||||
if strings.Split(strings.TrimSpace(header), "=")[0] == ConfigDefault.CookieName {
|
if strings.Split(utils.Trim(header, ' '), "=")[0] == ConfigDefault.CookieName {
|
||||||
token = strings.Split(header, "=")[1]
|
token = strings.Split(header, "=")[1]
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,67 +0,0 @@
|
||||||
package csrf
|
|
||||||
|
|
||||||
// Code generated by github.com/tinylib/msgp DO NOT EDIT.
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/tinylib/msgp/msgp"
|
|
||||||
)
|
|
||||||
|
|
||||||
func Test_MarshalUnmarshalitem(t *testing.T) {
|
|
||||||
v := item{}
|
|
||||||
bts, err := v.MarshalMsg(nil)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
left, err := v.UnmarshalMsg(bts)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
if len(left) > 0 {
|
|
||||||
t.Errorf("%d bytes left over after UnmarshalMsg(): %q", len(left), left)
|
|
||||||
}
|
|
||||||
|
|
||||||
left, err = msgp.Skip(bts)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
if len(left) > 0 {
|
|
||||||
t.Errorf("%d bytes left over after Skip(): %q", len(left), left)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Benchmark_MarshalMsgitem(b *testing.B) {
|
|
||||||
v := item{}
|
|
||||||
b.ReportAllocs()
|
|
||||||
b.ResetTimer()
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
v.MarshalMsg(nil)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Benchmark_AppendMsgitem(b *testing.B) {
|
|
||||||
v := item{}
|
|
||||||
bts := make([]byte, 0, v.Msgsize())
|
|
||||||
bts, _ = v.MarshalMsg(bts[0:0])
|
|
||||||
b.SetBytes(int64(len(bts)))
|
|
||||||
b.ReportAllocs()
|
|
||||||
b.ResetTimer()
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
bts, _ = v.MarshalMsg(bts[0:0])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Benchmark_Unmarshalitem(b *testing.B) {
|
|
||||||
v := item{}
|
|
||||||
bts, _ := v.MarshalMsg(nil)
|
|
||||||
b.ReportAllocs()
|
|
||||||
b.SetBytes(int64(len(bts)))
|
|
||||||
b.ResetTimer()
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
_, err := v.UnmarshalMsg(bts)
|
|
||||||
if err != nil {
|
|
||||||
b.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -9,15 +9,16 @@ import (
|
||||||
"github.com/gofiber/utils/v2"
|
"github.com/gofiber/utils/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
// go:generate msgp
|
// msgp -file="storage_manager.go" -o="storage_manager_msgp.go" -tests=true -unexported
|
||||||
// msgp -file="storage_manager.go" -o="storage_manager_msgp.go" -tests=false -unexported
|
//
|
||||||
|
//go:generate msgp
|
||||||
type item struct{}
|
type item struct{}
|
||||||
|
|
||||||
//msgp:ignore manager
|
//msgp:ignore manager
|
||||||
type storageManager struct {
|
type storageManager struct {
|
||||||
pool sync.Pool
|
pool sync.Pool `msg:"-"` //nolint:revive // Ignore unexported type
|
||||||
memory *memory.Storage
|
memory *memory.Storage `msg:"-"` //nolint:revive // Ignore unexported type
|
||||||
storage fiber.Storage
|
storage fiber.Storage `msg:"-"` //nolint:revive // Ignore unexported type
|
||||||
}
|
}
|
||||||
|
|
||||||
func newStorageManager(storage fiber.Storage) *storageManager {
|
func newStorageManager(storage fiber.Storage) *storageManager {
|
||||||
|
|
|
@ -6,10 +6,51 @@ import (
|
||||||
"github.com/tinylib/msgp/msgp"
|
"github.com/tinylib/msgp/msgp"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// DecodeMsg implements msgp.Decodable
|
||||||
|
func (z *item) DecodeMsg(dc *msgp.Reader) (err error) {
|
||||||
|
var field []byte
|
||||||
|
_ = field
|
||||||
|
var zb0001 uint32
|
||||||
|
zb0001, err = dc.ReadMapHeader()
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for zb0001 > 0 {
|
||||||
|
zb0001--
|
||||||
|
field, err = dc.ReadMapKeyPtr()
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch msgp.UnsafeString(field) {
|
||||||
|
default:
|
||||||
|
err = dc.Skip()
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// EncodeMsg implements msgp.Encodable
|
||||||
|
func (z item) EncodeMsg(en *msgp.Writer) (err error) {
|
||||||
|
// map header, size 0
|
||||||
|
_ = z
|
||||||
|
err = en.Append(0x80)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// MarshalMsg implements msgp.Marshaler
|
// MarshalMsg implements msgp.Marshaler
|
||||||
func (z item) MarshalMsg(b []byte) (o []byte, err error) {
|
func (z item) MarshalMsg(b []byte) (o []byte, err error) {
|
||||||
o = msgp.Require(b, z.Msgsize())
|
o = msgp.Require(b, z.Msgsize())
|
||||||
// map header, size 0
|
// map header, size 0
|
||||||
|
_ = z
|
||||||
o = append(o, 0x80)
|
o = append(o, 0x80)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -49,3 +90,88 @@ func (z item) Msgsize() (s int) {
|
||||||
s = 1
|
s = 1
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DecodeMsg implements msgp.Decodable
|
||||||
|
func (z *storageManager) DecodeMsg(dc *msgp.Reader) (err error) {
|
||||||
|
var field []byte
|
||||||
|
_ = field
|
||||||
|
var zb0001 uint32
|
||||||
|
zb0001, err = dc.ReadMapHeader()
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for zb0001 > 0 {
|
||||||
|
zb0001--
|
||||||
|
field, err = dc.ReadMapKeyPtr()
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch msgp.UnsafeString(field) {
|
||||||
|
default:
|
||||||
|
err = dc.Skip()
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// EncodeMsg implements msgp.Encodable
|
||||||
|
func (z storageManager) EncodeMsg(en *msgp.Writer) (err error) {
|
||||||
|
// map header, size 0
|
||||||
|
_ = z
|
||||||
|
err = en.Append(0x80)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalMsg implements msgp.Marshaler
|
||||||
|
func (z storageManager) MarshalMsg(b []byte) (o []byte, err error) {
|
||||||
|
o = msgp.Require(b, z.Msgsize())
|
||||||
|
// map header, size 0
|
||||||
|
_ = z
|
||||||
|
o = append(o, 0x80)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalMsg implements msgp.Unmarshaler
|
||||||
|
func (z *storageManager) UnmarshalMsg(bts []byte) (o []byte, err error) {
|
||||||
|
var field []byte
|
||||||
|
_ = field
|
||||||
|
var zb0001 uint32
|
||||||
|
zb0001, bts, err = msgp.ReadMapHeaderBytes(bts)
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for zb0001 > 0 {
|
||||||
|
zb0001--
|
||||||
|
field, bts, err = msgp.ReadMapKeyZC(bts)
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch msgp.UnsafeString(field) {
|
||||||
|
default:
|
||||||
|
bts, err = msgp.Skip(bts)
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
o = bts
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message
|
||||||
|
func (z storageManager) Msgsize() (s int) {
|
||||||
|
s = 1
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,236 @@
|
||||||
|
package csrf
|
||||||
|
|
||||||
|
// Code generated by github.com/tinylib/msgp DO NOT EDIT.
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/tinylib/msgp/msgp"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestMarshalUnmarshalitem(t *testing.T) {
|
||||||
|
v := item{}
|
||||||
|
bts, err := v.MarshalMsg(nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
left, err := v.UnmarshalMsg(bts)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(left) > 0 {
|
||||||
|
t.Errorf("%d bytes left over after UnmarshalMsg(): %q", len(left), left)
|
||||||
|
}
|
||||||
|
|
||||||
|
left, err = msgp.Skip(bts)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(left) > 0 {
|
||||||
|
t.Errorf("%d bytes left over after Skip(): %q", len(left), left)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkMarshalMsgitem(b *testing.B) {
|
||||||
|
v := item{}
|
||||||
|
b.ReportAllocs()
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
v.MarshalMsg(nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkAppendMsgitem(b *testing.B) {
|
||||||
|
v := item{}
|
||||||
|
bts := make([]byte, 0, v.Msgsize())
|
||||||
|
bts, _ = v.MarshalMsg(bts[0:0])
|
||||||
|
b.SetBytes(int64(len(bts)))
|
||||||
|
b.ReportAllocs()
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
bts, _ = v.MarshalMsg(bts[0:0])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkUnmarshalitem(b *testing.B) {
|
||||||
|
v := item{}
|
||||||
|
bts, _ := v.MarshalMsg(nil)
|
||||||
|
b.ReportAllocs()
|
||||||
|
b.SetBytes(int64(len(bts)))
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
_, err := v.UnmarshalMsg(bts)
|
||||||
|
if err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEncodeDecodeitem(t *testing.T) {
|
||||||
|
v := item{}
|
||||||
|
var buf bytes.Buffer
|
||||||
|
msgp.Encode(&buf, &v)
|
||||||
|
|
||||||
|
m := v.Msgsize()
|
||||||
|
if buf.Len() > m {
|
||||||
|
t.Log("WARNING: TestEncodeDecodeitem Msgsize() is inaccurate")
|
||||||
|
}
|
||||||
|
|
||||||
|
vn := item{}
|
||||||
|
err := msgp.Decode(&buf, &vn)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
buf.Reset()
|
||||||
|
msgp.Encode(&buf, &v)
|
||||||
|
err = msgp.NewReader(&buf).Skip()
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkEncodeitem(b *testing.B) {
|
||||||
|
v := item{}
|
||||||
|
var buf bytes.Buffer
|
||||||
|
msgp.Encode(&buf, &v)
|
||||||
|
b.SetBytes(int64(buf.Len()))
|
||||||
|
en := msgp.NewWriter(msgp.Nowhere)
|
||||||
|
b.ReportAllocs()
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
v.EncodeMsg(en)
|
||||||
|
}
|
||||||
|
en.Flush()
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkDecodeitem(b *testing.B) {
|
||||||
|
v := item{}
|
||||||
|
var buf bytes.Buffer
|
||||||
|
msgp.Encode(&buf, &v)
|
||||||
|
b.SetBytes(int64(buf.Len()))
|
||||||
|
rd := msgp.NewEndlessReader(buf.Bytes(), b)
|
||||||
|
dc := msgp.NewReader(rd)
|
||||||
|
b.ReportAllocs()
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
err := v.DecodeMsg(dc)
|
||||||
|
if err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMarshalUnmarshalstorageManager(t *testing.T) {
|
||||||
|
v := storageManager{}
|
||||||
|
bts, err := v.MarshalMsg(nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
left, err := v.UnmarshalMsg(bts)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(left) > 0 {
|
||||||
|
t.Errorf("%d bytes left over after UnmarshalMsg(): %q", len(left), left)
|
||||||
|
}
|
||||||
|
|
||||||
|
left, err = msgp.Skip(bts)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(left) > 0 {
|
||||||
|
t.Errorf("%d bytes left over after Skip(): %q", len(left), left)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkMarshalMsgstorageManager(b *testing.B) {
|
||||||
|
v := storageManager{}
|
||||||
|
b.ReportAllocs()
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
v.MarshalMsg(nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkAppendMsgstorageManager(b *testing.B) {
|
||||||
|
v := storageManager{}
|
||||||
|
bts := make([]byte, 0, v.Msgsize())
|
||||||
|
bts, _ = v.MarshalMsg(bts[0:0])
|
||||||
|
b.SetBytes(int64(len(bts)))
|
||||||
|
b.ReportAllocs()
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
bts, _ = v.MarshalMsg(bts[0:0])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkUnmarshalstorageManager(b *testing.B) {
|
||||||
|
v := storageManager{}
|
||||||
|
bts, _ := v.MarshalMsg(nil)
|
||||||
|
b.ReportAllocs()
|
||||||
|
b.SetBytes(int64(len(bts)))
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
_, err := v.UnmarshalMsg(bts)
|
||||||
|
if err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEncodeDecodestorageManager(t *testing.T) {
|
||||||
|
v := storageManager{}
|
||||||
|
var buf bytes.Buffer
|
||||||
|
msgp.Encode(&buf, &v)
|
||||||
|
|
||||||
|
m := v.Msgsize()
|
||||||
|
if buf.Len() > m {
|
||||||
|
t.Log("WARNING: TestEncodeDecodestorageManager Msgsize() is inaccurate")
|
||||||
|
}
|
||||||
|
|
||||||
|
vn := storageManager{}
|
||||||
|
err := msgp.Decode(&buf, &vn)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
buf.Reset()
|
||||||
|
msgp.Encode(&buf, &v)
|
||||||
|
err = msgp.NewReader(&buf).Skip()
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkEncodestorageManager(b *testing.B) {
|
||||||
|
v := storageManager{}
|
||||||
|
var buf bytes.Buffer
|
||||||
|
msgp.Encode(&buf, &v)
|
||||||
|
b.SetBytes(int64(buf.Len()))
|
||||||
|
en := msgp.NewWriter(msgp.Nowhere)
|
||||||
|
b.ReportAllocs()
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
v.EncodeMsg(en)
|
||||||
|
}
|
||||||
|
en.Flush()
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkDecodestorageManager(b *testing.B) {
|
||||||
|
v := storageManager{}
|
||||||
|
var buf bytes.Buffer
|
||||||
|
msgp.Encode(&buf, &v)
|
||||||
|
b.SetBytes(int64(buf.Len()))
|
||||||
|
rd := msgp.NewEndlessReader(buf.Bytes(), b)
|
||||||
|
dc := msgp.NewReader(rd)
|
||||||
|
b.ReportAllocs()
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
err := v.DecodeMsg(dc)
|
||||||
|
if err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,7 +3,7 @@ package idempotency
|
||||||
// response is a struct that represents the response of a request.
|
// response is a struct that represents the response of a request.
|
||||||
// generation tool `go install github.com/tinylib/msgp@latest`
|
// generation tool `go install github.com/tinylib/msgp@latest`
|
||||||
//
|
//
|
||||||
//go:generate msgp -o=response_msgp.go -io=false -unexported
|
//go:generate msgp -o=response_msgp.go -io=false -tests=true -unexported
|
||||||
type response struct {
|
type response struct {
|
||||||
Headers map[string][]string `msg:"hs"`
|
Headers map[string][]string `msg:"hs"`
|
||||||
|
|
||||||
|
|
|
@ -6,15 +6,151 @@ import (
|
||||||
"github.com/tinylib/msgp/msgp"
|
"github.com/tinylib/msgp/msgp"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// DecodeMsg implements msgp.Decodable
|
||||||
|
func (z *response) DecodeMsg(dc *msgp.Reader) (err error) {
|
||||||
|
var field []byte
|
||||||
|
_ = field
|
||||||
|
var zb0001 uint32
|
||||||
|
zb0001, err = dc.ReadMapHeader()
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for zb0001 > 0 {
|
||||||
|
zb0001--
|
||||||
|
field, err = dc.ReadMapKeyPtr()
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch msgp.UnsafeString(field) {
|
||||||
|
case "hs":
|
||||||
|
var zb0002 uint32
|
||||||
|
zb0002, err = dc.ReadMapHeader()
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err, "Headers")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if z.Headers == nil {
|
||||||
|
z.Headers = make(map[string][]string, zb0002)
|
||||||
|
} else if len(z.Headers) > 0 {
|
||||||
|
for key := range z.Headers {
|
||||||
|
delete(z.Headers, key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for zb0002 > 0 {
|
||||||
|
zb0002--
|
||||||
|
var za0001 string
|
||||||
|
var za0002 []string
|
||||||
|
za0001, err = dc.ReadString()
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err, "Headers")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var zb0003 uint32
|
||||||
|
zb0003, err = dc.ReadArrayHeader()
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err, "Headers", za0001)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if cap(za0002) >= int(zb0003) {
|
||||||
|
za0002 = (za0002)[:zb0003]
|
||||||
|
} else {
|
||||||
|
za0002 = make([]string, zb0003)
|
||||||
|
}
|
||||||
|
for za0003 := range za0002 {
|
||||||
|
za0002[za0003], err = dc.ReadString()
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err, "Headers", za0001, za0003)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
z.Headers[za0001] = za0002
|
||||||
|
}
|
||||||
|
case "b":
|
||||||
|
z.Body, err = dc.ReadBytes(z.Body)
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err, "Body")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
case "sc":
|
||||||
|
z.StatusCode, err = dc.ReadInt()
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err, "StatusCode")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
err = dc.Skip()
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// EncodeMsg implements msgp.Encodable
|
||||||
|
func (z *response) EncodeMsg(en *msgp.Writer) (err error) {
|
||||||
|
// map header, size 3
|
||||||
|
// write "hs"
|
||||||
|
err = en.Append(0x83, 0xa2, 0x68, 0x73)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = en.WriteMapHeader(uint32(len(z.Headers)))
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err, "Headers")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for za0001, za0002 := range z.Headers {
|
||||||
|
err = en.WriteString(za0001)
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err, "Headers")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = en.WriteArrayHeader(uint32(len(za0002)))
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err, "Headers", za0001)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for za0003 := range za0002 {
|
||||||
|
err = en.WriteString(za0002[za0003])
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err, "Headers", za0001, za0003)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// write "b"
|
||||||
|
err = en.Append(0xa1, 0x62)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = en.WriteBytes(z.Body)
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err, "Body")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// write "sc"
|
||||||
|
err = en.Append(0xa2, 0x73, 0x63)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = en.WriteInt(z.StatusCode)
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err, "StatusCode")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// MarshalMsg implements msgp.Marshaler
|
// MarshalMsg implements msgp.Marshaler
|
||||||
func (z *response) MarshalMsg(b []byte) (o []byte, err error) {
|
func (z *response) MarshalMsg(b []byte) (o []byte, err error) {
|
||||||
o = msgp.Require(b, z.Msgsize())
|
o = msgp.Require(b, z.Msgsize())
|
||||||
// map header, size 3
|
// map header, size 3
|
||||||
// string "sc"
|
|
||||||
o = append(o, 0x83, 0xa2, 0x73, 0x63)
|
|
||||||
o = msgp.AppendInt(o, z.StatusCode)
|
|
||||||
// string "hs"
|
// string "hs"
|
||||||
o = append(o, 0xa2, 0x68, 0x73)
|
o = append(o, 0x83, 0xa2, 0x68, 0x73)
|
||||||
o = msgp.AppendMapHeader(o, uint32(len(z.Headers)))
|
o = msgp.AppendMapHeader(o, uint32(len(z.Headers)))
|
||||||
for za0001, za0002 := range z.Headers {
|
for za0001, za0002 := range z.Headers {
|
||||||
o = msgp.AppendString(o, za0001)
|
o = msgp.AppendString(o, za0001)
|
||||||
|
@ -26,6 +162,9 @@ func (z *response) MarshalMsg(b []byte) (o []byte, err error) {
|
||||||
// string "b"
|
// string "b"
|
||||||
o = append(o, 0xa1, 0x62)
|
o = append(o, 0xa1, 0x62)
|
||||||
o = msgp.AppendBytes(o, z.Body)
|
o = msgp.AppendBytes(o, z.Body)
|
||||||
|
// string "sc"
|
||||||
|
o = append(o, 0xa2, 0x73, 0x63)
|
||||||
|
o = msgp.AppendInt(o, z.StatusCode)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,12 +186,6 @@ func (z *response) UnmarshalMsg(bts []byte) (o []byte, err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
switch msgp.UnsafeString(field) {
|
switch msgp.UnsafeString(field) {
|
||||||
case "sc":
|
|
||||||
z.StatusCode, bts, err = msgp.ReadIntBytes(bts)
|
|
||||||
if err != nil {
|
|
||||||
err = msgp.WrapError(err, "StatusCode")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
case "hs":
|
case "hs":
|
||||||
var zb0002 uint32
|
var zb0002 uint32
|
||||||
zb0002, bts, err = msgp.ReadMapHeaderBytes(bts)
|
zb0002, bts, err = msgp.ReadMapHeaderBytes(bts)
|
||||||
|
@ -102,6 +235,12 @@ func (z *response) UnmarshalMsg(bts []byte) (o []byte, err error) {
|
||||||
err = msgp.WrapError(err, "Body")
|
err = msgp.WrapError(err, "Body")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
case "sc":
|
||||||
|
z.StatusCode, bts, err = msgp.ReadIntBytes(bts)
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err, "StatusCode")
|
||||||
|
return
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
bts, err = msgp.Skip(bts)
|
bts, err = msgp.Skip(bts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -116,7 +255,7 @@ func (z *response) UnmarshalMsg(bts []byte) (o []byte, err error) {
|
||||||
|
|
||||||
// Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message
|
// Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message
|
||||||
func (z *response) Msgsize() (s int) {
|
func (z *response) Msgsize() (s int) {
|
||||||
s = 1 + 3 + msgp.IntSize + 3 + msgp.MapHeaderSize
|
s = 1 + 3 + msgp.MapHeaderSize
|
||||||
if z.Headers != nil {
|
if z.Headers != nil {
|
||||||
for za0001, za0002 := range z.Headers {
|
for za0001, za0002 := range z.Headers {
|
||||||
_ = za0002
|
_ = za0002
|
||||||
|
@ -126,6 +265,6 @@ func (z *response) Msgsize() (s int) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
s += 2 + msgp.BytesPrefixSize + len(z.Body)
|
s += 2 + msgp.BytesPrefixSize + len(z.Body) + 3 + msgp.IntSize
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ package idempotency
|
||||||
// Code generated by github.com/tinylib/msgp DO NOT EDIT.
|
// Code generated by github.com/tinylib/msgp DO NOT EDIT.
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/tinylib/msgp/msgp"
|
"github.com/tinylib/msgp/msgp"
|
||||||
|
@ -31,7 +32,7 @@ func TestMarshalUnmarshalresponse(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func Benchmark_MarshalMsgresponse(b *testing.B) {
|
func BenchmarkMarshalMsgresponse(b *testing.B) {
|
||||||
v := response{}
|
v := response{}
|
||||||
b.ReportAllocs()
|
b.ReportAllocs()
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
|
@ -40,7 +41,7 @@ func Benchmark_MarshalMsgresponse(b *testing.B) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func Benchmark_AppendMsgresponse(b *testing.B) {
|
func BenchmarkAppendMsgresponse(b *testing.B) {
|
||||||
v := response{}
|
v := response{}
|
||||||
bts := make([]byte, 0, v.Msgsize())
|
bts := make([]byte, 0, v.Msgsize())
|
||||||
bts, _ = v.MarshalMsg(bts[0:0])
|
bts, _ = v.MarshalMsg(bts[0:0])
|
||||||
|
@ -52,7 +53,7 @@ func Benchmark_AppendMsgresponse(b *testing.B) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func Benchmark_Unmarshalresponse(b *testing.B) {
|
func BenchmarkUnmarshalresponse(b *testing.B) {
|
||||||
v := response{}
|
v := response{}
|
||||||
bts, _ := v.MarshalMsg(nil)
|
bts, _ := v.MarshalMsg(nil)
|
||||||
b.ReportAllocs()
|
b.ReportAllocs()
|
||||||
|
@ -65,3 +66,58 @@ func Benchmark_Unmarshalresponse(b *testing.B) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestEncodeDecoderesponse(t *testing.T) {
|
||||||
|
v := response{}
|
||||||
|
var buf bytes.Buffer
|
||||||
|
msgp.Encode(&buf, &v)
|
||||||
|
|
||||||
|
m := v.Msgsize()
|
||||||
|
if buf.Len() > m {
|
||||||
|
t.Log("WARNING: TestEncodeDecoderesponse Msgsize() is inaccurate")
|
||||||
|
}
|
||||||
|
|
||||||
|
vn := response{}
|
||||||
|
err := msgp.Decode(&buf, &vn)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
buf.Reset()
|
||||||
|
msgp.Encode(&buf, &v)
|
||||||
|
err = msgp.NewReader(&buf).Skip()
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkEncoderesponse(b *testing.B) {
|
||||||
|
v := response{}
|
||||||
|
var buf bytes.Buffer
|
||||||
|
msgp.Encode(&buf, &v)
|
||||||
|
b.SetBytes(int64(buf.Len()))
|
||||||
|
en := msgp.NewWriter(msgp.Nowhere)
|
||||||
|
b.ReportAllocs()
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
v.EncodeMsg(en)
|
||||||
|
}
|
||||||
|
en.Flush()
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkDecoderesponse(b *testing.B) {
|
||||||
|
v := response{}
|
||||||
|
var buf bytes.Buffer
|
||||||
|
msgp.Encode(&buf, &v)
|
||||||
|
b.SetBytes(int64(buf.Len()))
|
||||||
|
rd := msgp.NewEndlessReader(buf.Bytes(), b)
|
||||||
|
dc := msgp.NewReader(rd)
|
||||||
|
b.ReportAllocs()
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
err := v.DecodeMsg(dc)
|
||||||
|
if err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -26,11 +26,11 @@ func (FixedWindow) New(cfg Config) fiber.Handler {
|
||||||
|
|
||||||
// Return new handler
|
// Return new handler
|
||||||
return func(c fiber.Ctx) error {
|
return func(c fiber.Ctx) error {
|
||||||
// Generate max from generator, if no generator was provided the default value returned is 5
|
// Generate maxRequests from generator, if no generator was provided the default value returned is 5
|
||||||
max := cfg.MaxFunc(c)
|
maxRequests := cfg.MaxFunc(c)
|
||||||
|
|
||||||
// Don't execute middleware if Next returns true or if the max is 0
|
// Don't execute middleware if Next returns true or if the max is 0
|
||||||
if (cfg.Next != nil && cfg.Next(c)) || max == 0 {
|
if (cfg.Next != nil && cfg.Next(c)) || maxRequests == 0 {
|
||||||
return c.Next()
|
return c.Next()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,7 +62,7 @@ func (FixedWindow) New(cfg Config) fiber.Handler {
|
||||||
resetInSec := e.exp - ts
|
resetInSec := e.exp - ts
|
||||||
|
|
||||||
// Set how many hits we have left
|
// Set how many hits we have left
|
||||||
remaining := max - e.currHits
|
remaining := maxRequests - e.currHits
|
||||||
|
|
||||||
// Update storage
|
// Update storage
|
||||||
manager.set(key, e, cfg.Expiration)
|
manager.set(key, e, cfg.Expiration)
|
||||||
|
@ -98,7 +98,7 @@ func (FixedWindow) New(cfg Config) fiber.Handler {
|
||||||
}
|
}
|
||||||
|
|
||||||
// We can continue, update RateLimit headers
|
// We can continue, update RateLimit headers
|
||||||
c.Set(xRateLimitLimit, strconv.Itoa(max))
|
c.Set(xRateLimitLimit, strconv.Itoa(maxRequests))
|
||||||
c.Set(xRateLimitRemaining, strconv.Itoa(remaining))
|
c.Set(xRateLimitRemaining, strconv.Itoa(remaining))
|
||||||
c.Set(xRateLimitReset, strconv.FormatUint(resetInSec, 10))
|
c.Set(xRateLimitReset, strconv.FormatUint(resetInSec, 10))
|
||||||
|
|
||||||
|
|
|
@ -27,11 +27,11 @@ func (SlidingWindow) New(cfg Config) fiber.Handler {
|
||||||
|
|
||||||
// Return new handler
|
// Return new handler
|
||||||
return func(c fiber.Ctx) error {
|
return func(c fiber.Ctx) error {
|
||||||
// Generate max from generator, if no generator was provided the default value returned is 5
|
// Generate maxRequests from generator, if no generator was provided the default value returned is 5
|
||||||
max := cfg.MaxFunc(c)
|
maxRequests := cfg.MaxFunc(c)
|
||||||
|
|
||||||
// Don't execute middleware if Next returns true or if the max is 0
|
// Don't execute middleware if Next returns true or if the max is 0
|
||||||
if (cfg.Next != nil && cfg.Next(c)) || max == 0 {
|
if (cfg.Next != nil && cfg.Next(c)) || maxRequests == 0 {
|
||||||
return c.Next()
|
return c.Next()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,7 +129,7 @@ func (SlidingWindow) New(cfg Config) fiber.Handler {
|
||||||
}
|
}
|
||||||
|
|
||||||
// We can continue, update RateLimit headers
|
// We can continue, update RateLimit headers
|
||||||
c.Set(xRateLimitLimit, strconv.Itoa(max))
|
c.Set(xRateLimitLimit, strconv.Itoa(maxRequests))
|
||||||
c.Set(xRateLimitRemaining, strconv.Itoa(remaining))
|
c.Set(xRateLimitRemaining, strconv.Itoa(remaining))
|
||||||
c.Set(xRateLimitReset, strconv.FormatUint(resetInSec, 10))
|
c.Set(xRateLimitReset, strconv.FormatUint(resetInSec, 10))
|
||||||
|
|
||||||
|
|
|
@ -97,11 +97,11 @@ func Test_Limiter_With_Max_Func_With_Zero(t *testing.T) {
|
||||||
func Test_Limiter_With_Max_Func(t *testing.T) {
|
func Test_Limiter_With_Max_Func(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
app := fiber.New()
|
app := fiber.New()
|
||||||
max := 10
|
maxRequests := 10
|
||||||
|
|
||||||
app.Use(New(Config{
|
app.Use(New(Config{
|
||||||
MaxFunc: func(_ fiber.Ctx) int {
|
MaxFunc: func(_ fiber.Ctx) int {
|
||||||
return max
|
return maxRequests
|
||||||
},
|
},
|
||||||
Expiration: 2 * time.Second,
|
Expiration: 2 * time.Second,
|
||||||
Storage: memory.New(),
|
Storage: memory.New(),
|
||||||
|
@ -113,7 +113,7 @@ func Test_Limiter_With_Max_Func(t *testing.T) {
|
||||||
|
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
|
|
||||||
for i := 0; i <= max-1; i++ {
|
for i := 0; i <= maxRequests-1; i++ {
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go func(wg *sync.WaitGroup) {
|
go func(wg *sync.WaitGroup) {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
|
|
|
@ -8,8 +8,9 @@ import (
|
||||||
"github.com/gofiber/fiber/v3/internal/memory"
|
"github.com/gofiber/fiber/v3/internal/memory"
|
||||||
)
|
)
|
||||||
|
|
||||||
// go:generate msgp
|
|
||||||
// msgp -file="manager.go" -o="manager_msgp.go" -tests=false -unexported
|
// msgp -file="manager.go" -o="manager_msgp.go" -tests=false -unexported
|
||||||
|
//
|
||||||
|
//go:generate msgp
|
||||||
type item struct {
|
type item struct {
|
||||||
currHits int
|
currHits int
|
||||||
prevHits int
|
prevHits int
|
||||||
|
|
|
@ -6,6 +6,89 @@ import (
|
||||||
"github.com/tinylib/msgp/msgp"
|
"github.com/tinylib/msgp/msgp"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// DecodeMsg implements msgp.Decodable
|
||||||
|
func (z *item) DecodeMsg(dc *msgp.Reader) (err error) {
|
||||||
|
var field []byte
|
||||||
|
_ = field
|
||||||
|
var zb0001 uint32
|
||||||
|
zb0001, err = dc.ReadMapHeader()
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for zb0001 > 0 {
|
||||||
|
zb0001--
|
||||||
|
field, err = dc.ReadMapKeyPtr()
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch msgp.UnsafeString(field) {
|
||||||
|
case "currHits":
|
||||||
|
z.currHits, err = dc.ReadInt()
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err, "currHits")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
case "prevHits":
|
||||||
|
z.prevHits, err = dc.ReadInt()
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err, "prevHits")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
case "exp":
|
||||||
|
z.exp, err = dc.ReadUint64()
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err, "exp")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
err = dc.Skip()
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// EncodeMsg implements msgp.Encodable
|
||||||
|
func (z item) EncodeMsg(en *msgp.Writer) (err error) {
|
||||||
|
// map header, size 3
|
||||||
|
// write "currHits"
|
||||||
|
err = en.Append(0x83, 0xa8, 0x63, 0x75, 0x72, 0x72, 0x48, 0x69, 0x74, 0x73)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = en.WriteInt(z.currHits)
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err, "currHits")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// write "prevHits"
|
||||||
|
err = en.Append(0xa8, 0x70, 0x72, 0x65, 0x76, 0x48, 0x69, 0x74, 0x73)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = en.WriteInt(z.prevHits)
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err, "prevHits")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// write "exp"
|
||||||
|
err = en.Append(0xa3, 0x65, 0x78, 0x70)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = en.WriteUint64(z.exp)
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err, "exp")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// MarshalMsg implements msgp.Marshaler
|
// MarshalMsg implements msgp.Marshaler
|
||||||
func (z item) MarshalMsg(b []byte) (o []byte, err error) {
|
func (z item) MarshalMsg(b []byte) (o []byte, err error) {
|
||||||
o = msgp.Require(b, z.Msgsize())
|
o = msgp.Require(b, z.Msgsize())
|
||||||
|
|
|
@ -3,12 +3,13 @@ package limiter
|
||||||
// Code generated by github.com/tinylib/msgp DO NOT EDIT.
|
// Code generated by github.com/tinylib/msgp DO NOT EDIT.
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/tinylib/msgp/msgp"
|
"github.com/tinylib/msgp/msgp"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Test_MarshalUnmarshalitem(t *testing.T) {
|
func TestMarshalUnmarshalitem(t *testing.T) {
|
||||||
v := item{}
|
v := item{}
|
||||||
bts, err := v.MarshalMsg(nil)
|
bts, err := v.MarshalMsg(nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -31,7 +32,7 @@ func Test_MarshalUnmarshalitem(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func Benchmark_MarshalMsgitem(b *testing.B) {
|
func BenchmarkMarshalMsgitem(b *testing.B) {
|
||||||
v := item{}
|
v := item{}
|
||||||
b.ReportAllocs()
|
b.ReportAllocs()
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
|
@ -40,7 +41,7 @@ func Benchmark_MarshalMsgitem(b *testing.B) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func Benchmark_AppendMsgitem(b *testing.B) {
|
func BenchmarkAppendMsgitem(b *testing.B) {
|
||||||
v := item{}
|
v := item{}
|
||||||
bts := make([]byte, 0, v.Msgsize())
|
bts := make([]byte, 0, v.Msgsize())
|
||||||
bts, _ = v.MarshalMsg(bts[0:0])
|
bts, _ = v.MarshalMsg(bts[0:0])
|
||||||
|
@ -52,7 +53,7 @@ func Benchmark_AppendMsgitem(b *testing.B) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func Benchmark_Unmarshalitem(b *testing.B) {
|
func BenchmarkUnmarshalitem(b *testing.B) {
|
||||||
v := item{}
|
v := item{}
|
||||||
bts, _ := v.MarshalMsg(nil)
|
bts, _ := v.MarshalMsg(nil)
|
||||||
b.ReportAllocs()
|
b.ReportAllocs()
|
||||||
|
@ -65,3 +66,58 @@ func Benchmark_Unmarshalitem(b *testing.B) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestEncodeDecodeitem(t *testing.T) {
|
||||||
|
v := item{}
|
||||||
|
var buf bytes.Buffer
|
||||||
|
msgp.Encode(&buf, &v)
|
||||||
|
|
||||||
|
m := v.Msgsize()
|
||||||
|
if buf.Len() > m {
|
||||||
|
t.Log("WARNING: TestEncodeDecodeitem Msgsize() is inaccurate")
|
||||||
|
}
|
||||||
|
|
||||||
|
vn := item{}
|
||||||
|
err := msgp.Decode(&buf, &vn)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
buf.Reset()
|
||||||
|
msgp.Encode(&buf, &v)
|
||||||
|
err = msgp.NewReader(&buf).Skip()
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkEncodeitem(b *testing.B) {
|
||||||
|
v := item{}
|
||||||
|
var buf bytes.Buffer
|
||||||
|
msgp.Encode(&buf, &v)
|
||||||
|
b.SetBytes(int64(buf.Len()))
|
||||||
|
en := msgp.NewWriter(msgp.Nowhere)
|
||||||
|
b.ReportAllocs()
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
v.EncodeMsg(en)
|
||||||
|
}
|
||||||
|
en.Flush()
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkDecodeitem(b *testing.B) {
|
||||||
|
v := item{}
|
||||||
|
var buf bytes.Buffer
|
||||||
|
msgp.Encode(&buf, &v)
|
||||||
|
b.SetBytes(int64(buf.Len()))
|
||||||
|
rd := msgp.NewEndlessReader(buf.Bytes(), b)
|
||||||
|
dc := msgp.NewReader(rd)
|
||||||
|
b.ReportAllocs()
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
err := v.DecodeMsg(dc)
|
||||||
|
if err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/gofiber/fiber/v3"
|
"github.com/gofiber/fiber/v3"
|
||||||
|
"github.com/gofiber/utils/v2"
|
||||||
"github.com/valyala/fasthttp/fasthttpadaptor"
|
"github.com/valyala/fasthttp/fasthttpadaptor"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -71,7 +72,7 @@ func New(config ...Config) fiber.Handler {
|
||||||
default:
|
default:
|
||||||
// pprof index only works with trailing slash
|
// pprof index only works with trailing slash
|
||||||
if strings.HasSuffix(path, "/") {
|
if strings.HasSuffix(path, "/") {
|
||||||
path = strings.TrimRight(path, "/")
|
path = utils.TrimRight(path, '/')
|
||||||
} else {
|
} else {
|
||||||
path = prefix + "/"
|
path = prefix + "/"
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
|
|
||||||
"github.com/gofiber/fiber/v3"
|
"github.com/gofiber/fiber/v3"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
"github.com/valyala/fasthttp"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Test_New(t *testing.T) {
|
func Test_New(t *testing.T) {
|
||||||
|
@ -170,3 +171,209 @@ func Test_Rewrite(t *testing.T) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, fiber.StatusNotFound, resp.StatusCode)
|
require.Equal(t, fiber.StatusNotFound, resp.StatusCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Benchmark_Rewrite(b *testing.B) {
|
||||||
|
// Helper function to create a new Fiber app with rewrite middleware
|
||||||
|
createApp := func(config Config) *fiber.App {
|
||||||
|
app := fiber.New()
|
||||||
|
app.Use(New(config))
|
||||||
|
return app
|
||||||
|
}
|
||||||
|
|
||||||
|
// Benchmark: Rewrite with Next function always returns true
|
||||||
|
b.Run("Next always true", func(b *testing.B) {
|
||||||
|
app := createApp(Config{
|
||||||
|
Next: func(fiber.Ctx) bool {
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
Rules: map[string]string{
|
||||||
|
"/old": "/new",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
reqCtx := &fasthttp.RequestCtx{}
|
||||||
|
reqCtx.Request.SetRequestURI("/old")
|
||||||
|
b.ReportAllocs()
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
app.Handler()(reqCtx)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// Benchmark: Rewrite with Next function always returns false
|
||||||
|
b.Run("Next always false", func(b *testing.B) {
|
||||||
|
app := createApp(Config{
|
||||||
|
Next: func(fiber.Ctx) bool {
|
||||||
|
return false
|
||||||
|
},
|
||||||
|
Rules: map[string]string{
|
||||||
|
"/old": "/new",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
reqCtx := &fasthttp.RequestCtx{}
|
||||||
|
reqCtx.Request.SetRequestURI("/old")
|
||||||
|
b.ReportAllocs()
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
app.Handler()(reqCtx)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// Benchmark: Rewrite with tokens
|
||||||
|
b.Run("Rewrite with tokens", func(b *testing.B) {
|
||||||
|
app := createApp(Config{
|
||||||
|
Rules: map[string]string{
|
||||||
|
"/users/*/orders/*": "/user/$1/order/$2",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
reqCtx := &fasthttp.RequestCtx{}
|
||||||
|
reqCtx.Request.SetRequestURI("/users/123/orders/456")
|
||||||
|
b.ReportAllocs()
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
app.Handler()(reqCtx)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// Benchmark: Non-matching request, handled by default route
|
||||||
|
b.Run("NonMatch with default", func(b *testing.B) {
|
||||||
|
app := createApp(Config{
|
||||||
|
Rules: map[string]string{
|
||||||
|
"/users/*/orders/*": "/user/$1/order/$2",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
app.Use(func(c fiber.Ctx) error {
|
||||||
|
return c.SendStatus(fiber.StatusOK)
|
||||||
|
})
|
||||||
|
|
||||||
|
reqCtx := &fasthttp.RequestCtx{}
|
||||||
|
reqCtx.Request.SetRequestURI("/not-matching-any-rule")
|
||||||
|
b.ReportAllocs()
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
app.Handler()(reqCtx)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// Benchmark: Non-matching request, with no default route
|
||||||
|
b.Run("NonMatch without default", func(b *testing.B) {
|
||||||
|
app := createApp(Config{
|
||||||
|
Rules: map[string]string{
|
||||||
|
"/users/*/orders/*": "/user/$1/order/$2",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
reqCtx := &fasthttp.RequestCtx{}
|
||||||
|
reqCtx.Request.SetRequestURI("/not-matching-any-rule")
|
||||||
|
b.ReportAllocs()
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
app.Handler()(reqCtx)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func Benchmark_Rewrite_Parallel(b *testing.B) {
|
||||||
|
// Helper function to create a new Fiber app with rewrite middleware
|
||||||
|
createApp := func(config Config) *fiber.App {
|
||||||
|
app := fiber.New()
|
||||||
|
app.Use(New(config))
|
||||||
|
return app
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parallel Benchmark: Rewrite with Next function always returns true
|
||||||
|
b.Run("Next always true", func(b *testing.B) {
|
||||||
|
app := createApp(Config{
|
||||||
|
Next: func(fiber.Ctx) bool {
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
Rules: map[string]string{
|
||||||
|
"/old": "/new",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
b.RunParallel(func(pb *testing.PB) {
|
||||||
|
reqCtx := &fasthttp.RequestCtx{}
|
||||||
|
reqCtx.Request.SetRequestURI("/old")
|
||||||
|
for pb.Next() {
|
||||||
|
app.Handler()(reqCtx)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
// Parallel Benchmark: Rewrite with Next function always returns false
|
||||||
|
b.Run("Next always false", func(b *testing.B) {
|
||||||
|
app := createApp(Config{
|
||||||
|
Next: func(fiber.Ctx) bool {
|
||||||
|
return false
|
||||||
|
},
|
||||||
|
Rules: map[string]string{
|
||||||
|
"/old": "/new",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
b.RunParallel(func(pb *testing.PB) {
|
||||||
|
reqCtx := &fasthttp.RequestCtx{}
|
||||||
|
reqCtx.Request.SetRequestURI("/old")
|
||||||
|
for pb.Next() {
|
||||||
|
app.Handler()(reqCtx)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
// Parallel Benchmark: Rewrite with tokens
|
||||||
|
b.Run("Rewrite with tokens", func(b *testing.B) {
|
||||||
|
app := createApp(Config{
|
||||||
|
Rules: map[string]string{
|
||||||
|
"/users/*/orders/*": "/user/$1/order/$2",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
b.RunParallel(func(pb *testing.PB) {
|
||||||
|
reqCtx := &fasthttp.RequestCtx{}
|
||||||
|
reqCtx.Request.SetRequestURI("/users/123/orders/456")
|
||||||
|
for pb.Next() {
|
||||||
|
app.Handler()(reqCtx)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
// Parallel Benchmark: Non-matching request, handled by default route
|
||||||
|
b.Run("NonMatch with default", func(b *testing.B) {
|
||||||
|
app := createApp(Config{
|
||||||
|
Rules: map[string]string{
|
||||||
|
"/users/*/orders/*": "/user/$1/order/$2",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
app.Use(func(c fiber.Ctx) error {
|
||||||
|
return c.SendStatus(fiber.StatusOK)
|
||||||
|
})
|
||||||
|
|
||||||
|
b.RunParallel(func(pb *testing.PB) {
|
||||||
|
reqCtx := &fasthttp.RequestCtx{}
|
||||||
|
reqCtx.Request.SetRequestURI("/not-matching-any-rule")
|
||||||
|
for pb.Next() {
|
||||||
|
app.Handler()(reqCtx)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
// Parallel Benchmark: Non-matching request, with no default route
|
||||||
|
b.Run("NonMatch without default", func(b *testing.B) {
|
||||||
|
app := createApp(Config{
|
||||||
|
Rules: map[string]string{
|
||||||
|
"/users/*/orders/*": "/user/$1/order/$2",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
b.RunParallel(func(pb *testing.PB) {
|
||||||
|
reqCtx := &fasthttp.RequestCtx{}
|
||||||
|
reqCtx.Request.SetRequestURI("/not-matching-any-rule")
|
||||||
|
for pb.Next() {
|
||||||
|
app.Handler()(reqCtx)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
@ -4,11 +4,12 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
// go:generate msgp
|
// msgp -file="data.go" -o="data_msgp.go" -tests=true -unexported
|
||||||
// msgp -file="data.go" -o="data_msgp.go" -tests=false -unexported
|
//
|
||||||
|
//go:generate msgp
|
||||||
type data struct {
|
type data struct {
|
||||||
Data map[string]any
|
Data map[string]any
|
||||||
sync.RWMutex
|
sync.RWMutex `msg:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
var dataPool = sync.Pool{
|
var dataPool = sync.Pool{
|
||||||
|
|
|
@ -0,0 +1,184 @@
|
||||||
|
package session
|
||||||
|
|
||||||
|
// Code generated by github.com/tinylib/msgp DO NOT EDIT.
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/tinylib/msgp/msgp"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DecodeMsg implements msgp.Decodable
|
||||||
|
func (z *data) DecodeMsg(dc *msgp.Reader) (err error) {
|
||||||
|
var field []byte
|
||||||
|
_ = field
|
||||||
|
var zb0001 uint32
|
||||||
|
zb0001, err = dc.ReadMapHeader()
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for zb0001 > 0 {
|
||||||
|
zb0001--
|
||||||
|
field, err = dc.ReadMapKeyPtr()
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch msgp.UnsafeString(field) {
|
||||||
|
case "Data":
|
||||||
|
var zb0002 uint32
|
||||||
|
zb0002, err = dc.ReadMapHeader()
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err, "Data")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if z.Data == nil {
|
||||||
|
z.Data = make(map[string]interface{}, zb0002)
|
||||||
|
} else if len(z.Data) > 0 {
|
||||||
|
for key := range z.Data {
|
||||||
|
delete(z.Data, key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for zb0002 > 0 {
|
||||||
|
zb0002--
|
||||||
|
var za0001 string
|
||||||
|
var za0002 interface{}
|
||||||
|
za0001, err = dc.ReadString()
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err, "Data")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
za0002, err = dc.ReadIntf()
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err, "Data", za0001)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
z.Data[za0001] = za0002
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
err = dc.Skip()
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// EncodeMsg implements msgp.Encodable
|
||||||
|
func (z *data) EncodeMsg(en *msgp.Writer) (err error) {
|
||||||
|
// map header, size 1
|
||||||
|
// write "Data"
|
||||||
|
err = en.Append(0x81, 0xa4, 0x44, 0x61, 0x74, 0x61)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = en.WriteMapHeader(uint32(len(z.Data)))
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err, "Data")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for za0001, za0002 := range z.Data {
|
||||||
|
err = en.WriteString(za0001)
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err, "Data")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = en.WriteIntf(za0002)
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err, "Data", za0001)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalMsg implements msgp.Marshaler
|
||||||
|
func (z *data) MarshalMsg(b []byte) (o []byte, err error) {
|
||||||
|
o = msgp.Require(b, z.Msgsize())
|
||||||
|
// map header, size 1
|
||||||
|
// string "Data"
|
||||||
|
o = append(o, 0x81, 0xa4, 0x44, 0x61, 0x74, 0x61)
|
||||||
|
o = msgp.AppendMapHeader(o, uint32(len(z.Data)))
|
||||||
|
for za0001, za0002 := range z.Data {
|
||||||
|
o = msgp.AppendString(o, za0001)
|
||||||
|
o, err = msgp.AppendIntf(o, za0002)
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err, "Data", za0001)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalMsg implements msgp.Unmarshaler
|
||||||
|
func (z *data) UnmarshalMsg(bts []byte) (o []byte, err error) {
|
||||||
|
var field []byte
|
||||||
|
_ = field
|
||||||
|
var zb0001 uint32
|
||||||
|
zb0001, bts, err = msgp.ReadMapHeaderBytes(bts)
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for zb0001 > 0 {
|
||||||
|
zb0001--
|
||||||
|
field, bts, err = msgp.ReadMapKeyZC(bts)
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch msgp.UnsafeString(field) {
|
||||||
|
case "Data":
|
||||||
|
var zb0002 uint32
|
||||||
|
zb0002, bts, err = msgp.ReadMapHeaderBytes(bts)
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err, "Data")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if z.Data == nil {
|
||||||
|
z.Data = make(map[string]interface{}, zb0002)
|
||||||
|
} else if len(z.Data) > 0 {
|
||||||
|
for key := range z.Data {
|
||||||
|
delete(z.Data, key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for zb0002 > 0 {
|
||||||
|
var za0001 string
|
||||||
|
var za0002 interface{}
|
||||||
|
zb0002--
|
||||||
|
za0001, bts, err = msgp.ReadStringBytes(bts)
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err, "Data")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
za0002, bts, err = msgp.ReadIntfBytes(bts)
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err, "Data", za0001)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
z.Data[za0001] = za0002
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
bts, err = msgp.Skip(bts)
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
o = bts
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message
|
||||||
|
func (z *data) Msgsize() (s int) {
|
||||||
|
s = 1 + 5 + msgp.MapHeaderSize
|
||||||
|
if z.Data != nil {
|
||||||
|
for za0001, za0002 := range z.Data {
|
||||||
|
_ = za0002
|
||||||
|
s += msgp.StringPrefixSize + len(za0001) + msgp.GuessSize(za0002)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
|
@ -0,0 +1,123 @@
|
||||||
|
package session
|
||||||
|
|
||||||
|
// Code generated by github.com/tinylib/msgp DO NOT EDIT.
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/tinylib/msgp/msgp"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestMarshalUnmarshaldata(t *testing.T) {
|
||||||
|
v := data{}
|
||||||
|
bts, err := v.MarshalMsg(nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
left, err := v.UnmarshalMsg(bts)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(left) > 0 {
|
||||||
|
t.Errorf("%d bytes left over after UnmarshalMsg(): %q", len(left), left)
|
||||||
|
}
|
||||||
|
|
||||||
|
left, err = msgp.Skip(bts)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(left) > 0 {
|
||||||
|
t.Errorf("%d bytes left over after Skip(): %q", len(left), left)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkMarshalMsgdata(b *testing.B) {
|
||||||
|
v := data{}
|
||||||
|
b.ReportAllocs()
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
v.MarshalMsg(nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkAppendMsgdata(b *testing.B) {
|
||||||
|
v := data{}
|
||||||
|
bts := make([]byte, 0, v.Msgsize())
|
||||||
|
bts, _ = v.MarshalMsg(bts[0:0])
|
||||||
|
b.SetBytes(int64(len(bts)))
|
||||||
|
b.ReportAllocs()
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
bts, _ = v.MarshalMsg(bts[0:0])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkUnmarshaldata(b *testing.B) {
|
||||||
|
v := data{}
|
||||||
|
bts, _ := v.MarshalMsg(nil)
|
||||||
|
b.ReportAllocs()
|
||||||
|
b.SetBytes(int64(len(bts)))
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
_, err := v.UnmarshalMsg(bts)
|
||||||
|
if err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEncodeDecodedata(t *testing.T) {
|
||||||
|
v := data{}
|
||||||
|
var buf bytes.Buffer
|
||||||
|
msgp.Encode(&buf, &v)
|
||||||
|
|
||||||
|
m := v.Msgsize()
|
||||||
|
if buf.Len() > m {
|
||||||
|
t.Log("WARNING: TestEncodeDecodedata Msgsize() is inaccurate")
|
||||||
|
}
|
||||||
|
|
||||||
|
vn := data{}
|
||||||
|
err := msgp.Decode(&buf, &vn)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
buf.Reset()
|
||||||
|
msgp.Encode(&buf, &v)
|
||||||
|
err = msgp.NewReader(&buf).Skip()
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkEncodedata(b *testing.B) {
|
||||||
|
v := data{}
|
||||||
|
var buf bytes.Buffer
|
||||||
|
msgp.Encode(&buf, &v)
|
||||||
|
b.SetBytes(int64(buf.Len()))
|
||||||
|
en := msgp.NewWriter(msgp.Nowhere)
|
||||||
|
b.ReportAllocs()
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
v.EncodeMsg(en)
|
||||||
|
}
|
||||||
|
en.Flush()
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkDecodedata(b *testing.B) {
|
||||||
|
v := data{}
|
||||||
|
var buf bytes.Buffer
|
||||||
|
msgp.Encode(&buf, &v)
|
||||||
|
b.SetBytes(int64(buf.Len()))
|
||||||
|
rd := msgp.NewEndlessReader(buf.Bytes(), b)
|
||||||
|
dc := msgp.NewReader(rd)
|
||||||
|
b.ReportAllocs()
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
err := v.DecodeMsg(dc)
|
||||||
|
if err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -86,7 +86,7 @@ func configDefault(config ...Config) Config {
|
||||||
cfg := config[0]
|
cfg := config[0]
|
||||||
|
|
||||||
// Set default values
|
// Set default values
|
||||||
if cfg.IndexNames == nil || len(cfg.IndexNames) == 0 {
|
if len(cfg.IndexNames) == 0 {
|
||||||
cfg.IndexNames = ConfigDefault.IndexNames
|
cfg.IndexNames = ConfigDefault.IndexNames
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
7
mount.go
7
mount.go
|
@ -6,9 +6,10 @@ package fiber
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
|
||||||
|
"github.com/gofiber/utils/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Put fields related to mounting.
|
// Put fields related to mounting.
|
||||||
|
@ -39,7 +40,7 @@ func newMountFields(app *App) *mountFields {
|
||||||
// any of the fiber's sub apps are added to the application's error handlers
|
// any of the fiber's sub apps are added to the application's error handlers
|
||||||
// to be invoked on errors that happen within the prefix route.
|
// to be invoked on errors that happen within the prefix route.
|
||||||
func (app *App) mount(prefix string, subApp *App) Router {
|
func (app *App) mount(prefix string, subApp *App) Router {
|
||||||
prefix = strings.TrimRight(prefix, "/")
|
prefix = utils.TrimRight(prefix, '/')
|
||||||
if prefix == "" {
|
if prefix == "" {
|
||||||
prefix = "/"
|
prefix = "/"
|
||||||
}
|
}
|
||||||
|
@ -69,7 +70,7 @@ func (app *App) mount(prefix string, subApp *App) Router {
|
||||||
// compose them as a single service using Mount.
|
// compose them as a single service using Mount.
|
||||||
func (grp *Group) mount(prefix string, subApp *App) Router {
|
func (grp *Group) mount(prefix string, subApp *App) Router {
|
||||||
groupPath := getGroupPath(grp.Prefix, prefix)
|
groupPath := getGroupPath(grp.Prefix, prefix)
|
||||||
groupPath = strings.TrimRight(groupPath, "/")
|
groupPath = utils.TrimRight(groupPath, '/')
|
||||||
if groupPath == "" {
|
if groupPath == "" {
|
||||||
groupPath = "/"
|
groupPath = "/"
|
||||||
}
|
}
|
||||||
|
|
6
path.go
6
path.go
|
@ -51,7 +51,7 @@ const (
|
||||||
optionalParam byte = '?' // concludes a parameter by name and makes it optional
|
optionalParam byte = '?' // concludes a parameter by name and makes it optional
|
||||||
paramStarterChar byte = ':' // start character for a parameter with name
|
paramStarterChar byte = ':' // start character for a parameter with name
|
||||||
slashDelimiter byte = '/' // separator for the route, unlike the other delimiters this character at the end can be optional
|
slashDelimiter byte = '/' // separator for the route, unlike the other delimiters this character at the end can be optional
|
||||||
slashDelimiterStr = "/" // separator for the route, unlike the other delimiters this character at the end can be optional
|
slashDelimiterStr byte = '/' // separator for the route, unlike the other delimiters this character at the end can be optional
|
||||||
escapeChar byte = '\\' // escape character
|
escapeChar byte = '\\' // escape character
|
||||||
paramConstraintStart byte = '<' // start of type constraint for a parameter
|
paramConstraintStart byte = '<' // start of type constraint for a parameter
|
||||||
paramConstraintEnd byte = '>' // end of type constraint for a parameter
|
paramConstraintEnd byte = '>' // end of type constraint for a parameter
|
||||||
|
@ -161,7 +161,7 @@ func RoutePatternMatch(path, pattern string, cfg ...Config) bool {
|
||||||
}
|
}
|
||||||
// Strict routing, remove trailing slashes
|
// Strict routing, remove trailing slashes
|
||||||
if !config.StrictRouting && len(patternPretty) > 1 {
|
if !config.StrictRouting && len(patternPretty) > 1 {
|
||||||
patternPretty = strings.TrimRight(patternPretty, "/")
|
patternPretty = utils.TrimRight(patternPretty, '/')
|
||||||
}
|
}
|
||||||
|
|
||||||
parser := parseRoute(patternPretty)
|
parser := parseRoute(patternPretty)
|
||||||
|
@ -233,7 +233,7 @@ func addParameterMetaInfo(segs []*routeSegment) []*routeSegment {
|
||||||
} else {
|
} else {
|
||||||
comparePart = segs[i].Const
|
comparePart = segs[i].Const
|
||||||
if len(comparePart) > 1 {
|
if len(comparePart) > 1 {
|
||||||
comparePart = strings.TrimRight(comparePart, slashDelimiterStr)
|
comparePart = utils.TrimRight(comparePart, slashDelimiterStr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
13
path_test.go
13
path_test.go
|
@ -5,7 +5,6 @@
|
||||||
package fiber
|
package fiber
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
@ -142,9 +141,9 @@ func Test_Path_matchParams(t *testing.T) {
|
||||||
parser := parseRoute(testCollection.pattern)
|
parser := parseRoute(testCollection.pattern)
|
||||||
for _, c := range testCollection.testCases {
|
for _, c := range testCollection.testCases {
|
||||||
match := parser.getMatch(c.url, c.url, &ctxParams, c.partialCheck)
|
match := parser.getMatch(c.url, c.url, &ctxParams, c.partialCheck)
|
||||||
require.Equal(t, c.match, match, fmt.Sprintf("route: '%s', url: '%s'", testCollection.pattern, c.url))
|
require.Equal(t, c.match, match, "route: '%s', url: '%s'", testCollection.pattern, c.url)
|
||||||
if match && len(c.params) > 0 {
|
if match && len(c.params) > 0 {
|
||||||
require.Equal(t, c.params[0:len(c.params)], ctxParams[0:len(c.params)], fmt.Sprintf("route: '%s', url: '%s'", testCollection.pattern, c.url))
|
require.Equal(t, c.params[0:len(c.params)], ctxParams[0:len(c.params)], "route: '%s', url: '%s'", testCollection.pattern, c.url)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -163,7 +162,7 @@ func Test_RoutePatternMatch(t *testing.T) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
match := RoutePatternMatch(c.url, pattern)
|
match := RoutePatternMatch(c.url, pattern)
|
||||||
require.Equal(t, c.match, match, fmt.Sprintf("route: '%s', url: '%s'", pattern, c.url))
|
require.Equal(t, c.match, match, "route: '%s', url: '%s'", pattern, c.url)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, testCase := range routeTestCases {
|
for _, testCase := range routeTestCases {
|
||||||
|
@ -224,9 +223,9 @@ func Benchmark_Path_matchParams(t *testing.B) {
|
||||||
matchRes = true
|
matchRes = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
require.Equal(t, c.match, matchRes, fmt.Sprintf("route: '%s', url: '%s'", testCollection.pattern, c.url))
|
require.Equal(t, c.match, matchRes, "route: '%s', url: '%s'", testCollection.pattern, c.url)
|
||||||
if matchRes && len(c.params) > 0 {
|
if matchRes && len(c.params) > 0 {
|
||||||
require.Equal(t, c.params[0:len(c.params)-1], ctxParams[0:len(c.params)-1], fmt.Sprintf("route: '%s', url: '%s'", testCollection.pattern, c.url))
|
require.Equal(t, c.params[0:len(c.params)-1], ctxParams[0:len(c.params)-1], "route: '%s', url: '%s'", testCollection.pattern, c.url)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -257,7 +256,7 @@ func Benchmark_RoutePatternMatch(t *testing.B) {
|
||||||
matchRes = true
|
matchRes = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
require.Equal(t, c.match, matchRes, fmt.Sprintf("route: '%s', url: '%s'", testCollection.pattern, c.url))
|
require.Equal(t, c.match, matchRes, "route: '%s', url: '%s'", testCollection.pattern, c.url)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,9 +76,9 @@ func (app *App) prefork(addr string, tlsConfig *tls.Config, cfg ListenConfig) er
|
||||||
pid int
|
pid int
|
||||||
}
|
}
|
||||||
// create variables
|
// create variables
|
||||||
max := runtime.GOMAXPROCS(0)
|
maxProcs := runtime.GOMAXPROCS(0)
|
||||||
childs := make(map[int]*exec.Cmd)
|
childs := make(map[int]*exec.Cmd)
|
||||||
channel := make(chan child, max)
|
channel := make(chan child, maxProcs)
|
||||||
|
|
||||||
// kill child procs when master exits
|
// kill child procs when master exits
|
||||||
defer func() {
|
defer func() {
|
||||||
|
@ -95,7 +95,7 @@ func (app *App) prefork(addr string, tlsConfig *tls.Config, cfg ListenConfig) er
|
||||||
var pids []string
|
var pids []string
|
||||||
|
|
||||||
// launch child procs
|
// launch child procs
|
||||||
for i := 0; i < max; i++ {
|
for i := 0; i < maxProcs; i++ {
|
||||||
cmd := exec.Command(os.Args[0], os.Args[1:]...) //nolint:gosec // It's fine to launch the same process again
|
cmd := exec.Command(os.Args[0], os.Args[1:]...) //nolint:gosec // It's fine to launch the same process again
|
||||||
if testPreforkMaster {
|
if testPreforkMaster {
|
||||||
// When test prefork master,
|
// When test prefork master,
|
||||||
|
|
|
@ -95,11 +95,11 @@ func Test_App_Prefork_Child_Process_Never_Show_Startup_Message(t *testing.T) {
|
||||||
func setupIsChild(t *testing.T) {
|
func setupIsChild(t *testing.T) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
require.NoError(t, os.Setenv(envPreforkChildKey, envPreforkChildVal))
|
require.NoError(t, os.Setenv(envPreforkChildKey, envPreforkChildVal)) //nolint:tenv // Ignore error
|
||||||
}
|
}
|
||||||
|
|
||||||
func teardownIsChild(t *testing.T) {
|
func teardownIsChild(t *testing.T) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
require.NoError(t, os.Setenv(envPreforkChildKey, ""))
|
require.NoError(t, os.Setenv(envPreforkChildKey, "")) //nolint:tenv // Ignore error
|
||||||
}
|
}
|
||||||
|
|
|
@ -249,10 +249,10 @@ func (r *Redirect) parseAndClearFlashMessages() {
|
||||||
for {
|
for {
|
||||||
commaPos = findNextNonEscapedCharsetPosition(cookieValue, []byte(CookieDataSeparator))
|
commaPos = findNextNonEscapedCharsetPosition(cookieValue, []byte(CookieDataSeparator))
|
||||||
if commaPos == -1 {
|
if commaPos == -1 {
|
||||||
r.c.redirectionMessages = append(r.c.redirectionMessages, strings.Trim(cookieValue, " "))
|
r.c.redirectionMessages = append(r.c.redirectionMessages, utils.Trim(cookieValue, ' '))
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
r.c.redirectionMessages = append(r.c.redirectionMessages, strings.Trim(cookieValue[:commaPos], " "))
|
r.c.redirectionMessages = append(r.c.redirectionMessages, utils.Trim(cookieValue[:commaPos], ' '))
|
||||||
cookieValue = cookieValue[commaPos+1:]
|
cookieValue = cookieValue[commaPos+1:]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -253,7 +253,7 @@ func (app *App) addPrefixToRoute(prefix string, route *Route) *Route {
|
||||||
}
|
}
|
||||||
// Strict routing, remove trailing slashes
|
// Strict routing, remove trailing slashes
|
||||||
if !app.config.StrictRouting && len(prettyPath) > 1 {
|
if !app.config.StrictRouting && len(prettyPath) > 1 {
|
||||||
prettyPath = strings.TrimRight(prettyPath, "/")
|
prettyPath = utils.TrimRight(prettyPath, '/')
|
||||||
}
|
}
|
||||||
|
|
||||||
route.Path = prefixedPath
|
route.Path = prefixedPath
|
||||||
|
@ -324,7 +324,7 @@ func (app *App) register(methods []string, pathRaw string, group *Group, handler
|
||||||
}
|
}
|
||||||
// Strict routing, remove trailing slashes
|
// Strict routing, remove trailing slashes
|
||||||
if !app.config.StrictRouting && len(pathPretty) > 1 {
|
if !app.config.StrictRouting && len(pathPretty) > 1 {
|
||||||
pathPretty = strings.TrimRight(pathPretty, "/")
|
pathPretty = utils.TrimRight(pathPretty, '/')
|
||||||
}
|
}
|
||||||
// Is layer a middleware?
|
// Is layer a middleware?
|
||||||
isUse := method == methodUse
|
isUse := method == methodUse
|
||||||
|
|
Loading…
Reference in New Issue