Skip to content

Commit

Permalink
v3: Improve Performance of c.Body() by 125% (#3090)
Browse files Browse the repository at this point in the history
* Improve performance of Body()

* Add unit-test and benchmark for BodyRaw() with Immutable
  • Loading branch information
gaby authored Jul 25, 2024
1 parent fadedcb commit 0592e01
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 5 deletions.
14 changes: 9 additions & 5 deletions ctx.go
Original file line number Diff line number Diff line change
Expand Up @@ -339,12 +339,16 @@ func (c *DefaultCtx) Body() []byte {
encodingOrder = []string{"", "", ""}
)

// faster than peek
c.Request().Header.VisitAll(func(key, value []byte) {
if c.app.getString(key) == HeaderContentEncoding {
headerEncoding = c.app.getString(value)
// Get Content-Encoding header
headerEncoding = utils.UnsafeString(c.Request().Header.ContentEncoding())

// If no encoding is provided, return the original body
if len(headerEncoding) == 0 {
if c.app.config.Immutable {
return utils.CopyBytes(c.fasthttp.Request.Body())
}
})
return c.fasthttp.Request.Body()
}

// 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
Expand Down
54 changes: 54 additions & 0 deletions ctx_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,26 @@ func Test_Ctx_Body(t *testing.T) {
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
func Benchmark_Ctx_Body(b *testing.B) {
const input = "john=doe"
Expand All @@ -373,6 +393,40 @@ func Benchmark_Ctx_Body(b *testing.B) {
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
func Test_Ctx_Body_Immutable(t *testing.T) {
t.Parallel()
Expand Down

1 comment on commit 0592e01

@github-actions
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Performance Alert ⚠️

Possible performance regression was detected for benchmark.
Benchmark result of this commit is worse than the previous benchmark result exceeding threshold 1.50.

Benchmark suite Current: 0592e01 Previous: 87bb93e Ratio
Benchmark_Middleware_BasicAuth - B/op 80 B/op 48 B/op 1.67
Benchmark_Middleware_BasicAuth - allocs/op 5 allocs/op 3 allocs/op 1.67
Benchmark_Middleware_BasicAuth_Upper - B/op 80 B/op 48 B/op 1.67
Benchmark_Middleware_BasicAuth_Upper - allocs/op 5 allocs/op 3 allocs/op 1.67
Benchmark_CORS_NewHandler - B/op 16 B/op 0 B/op +∞
Benchmark_CORS_NewHandler - allocs/op 1 allocs/op 0 allocs/op +∞
Benchmark_CORS_NewHandlerSingleOrigin - B/op 16 B/op 0 B/op +∞
Benchmark_CORS_NewHandlerSingleOrigin - allocs/op 1 allocs/op 0 allocs/op +∞
Benchmark_CORS_NewHandlerPreflight - B/op 104 B/op 0 B/op +∞
Benchmark_CORS_NewHandlerPreflight - allocs/op 5 allocs/op 0 allocs/op +∞
Benchmark_CORS_NewHandlerPreflightSingleOrigin - B/op 104 B/op 0 B/op +∞
Benchmark_CORS_NewHandlerPreflightSingleOrigin - allocs/op 5 allocs/op 0 allocs/op +∞
Benchmark_CORS_NewHandlerPreflightWildcard 1043 ns/op 104 B/op 5 allocs/op 691 ns/op 0 B/op 0 allocs/op 1.51
Benchmark_CORS_NewHandlerPreflightWildcard - ns/op 1043 ns/op 691 ns/op 1.51
Benchmark_CORS_NewHandlerPreflightWildcard - B/op 104 B/op 0 B/op +∞
Benchmark_CORS_NewHandlerPreflightWildcard - allocs/op 5 allocs/op 0 allocs/op +∞
Benchmark_Middleware_CSRF_Check - allocs/op 11 allocs/op 7 allocs/op 1.57
Benchmark_Middleware_CSRF_GenerateToken - B/op 511 B/op 326 B/op 1.57
Benchmark_Middleware_CSRF_GenerateToken - allocs/op 10 allocs/op 6 allocs/op 1.67

This comment was automatically generated by workflow using github-action-benchmark.

Please sign in to comment.