Added decompression cases for Body function (#1402)

* Added decompression cases for Body function

* Fixed signature of Body() function

* Removed regex, added Header.Peek

* Added test case with compression

* Added Benchmark, moved compression names to helpers and made them constants

* Added long brotli as a constant

* Update ctx.go

improve Body function

* Update ctx.go

improve performance

* Fixed formatting

* Update helpers.go

Co-authored-by: RW <rene@gofiber.io>
pull/1404/head
Andreas 2021-06-24 08:47:21 +03:00 committed by GitHub
parent 843fab720e
commit 2703e92c5d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 81 additions and 1 deletions

28
ctx.go
View File

@ -33,6 +33,7 @@ const maxParams = 30
const queryTag = "query"
// Ctx represents the Context which hold the HTTP request and response.
// It has methods for the request query string, parameters, body, HTTP headers and so on.
type Ctx struct {
@ -239,7 +240,32 @@ func (c *Ctx) BaseURL() string {
// Returned value is only valid within the handler. Do not store any references.
// Make copies or use the Immutable setting instead.
func (c *Ctx) Body() []byte {
return c.fasthttp.Request.Body()
var err error
var encoding string
var body []byte
// faster than peek
c.Request().Header.VisitAll(func(key, value []byte) {
if utils.UnsafeString(key) == HeaderContentEncoding {
encoding = utils.UnsafeString(value)
}
})
switch encoding {
case StrGzip:
body, err = c.fasthttp.Request.BodyGunzip()
case StrBr, StrBrotli:
body, err = c.fasthttp.Request.BodyUnbrotli()
case StrDeflate:
body, err = c.fasthttp.Request.BodyInflate()
default:
body = c.fasthttp.Request.Body()
}
if err != nil {
return []byte(err.Error())
}
return body
}
// decoderPool helps to improve BodyParser's and QueryParser's performance

View File

@ -10,6 +10,7 @@ package fiber
import (
"bufio"
"bytes"
"compress/gzip"
"context"
"errors"
"fmt"
@ -303,6 +304,49 @@ func Test_Ctx_Body(t *testing.T) {
utils.AssertEqual(t, []byte("john=doe"), c.Body())
}
// go test -run Test_Ctx_Body_With_Compression
func Test_Ctx_Body_With_Compression(t *testing.T) {
t.Parallel()
app := New()
c := app.AcquireCtx(&fasthttp.RequestCtx{})
defer app.ReleaseCtx(c)
c.Request().Header.Set("Content-Encoding", "gzip")
var b bytes.Buffer
gz := gzip.NewWriter(&b)
_, err := gz.Write([]byte("john=doe"))
utils.AssertEqual(t, nil, err)
err = gz.Flush()
utils.AssertEqual(t, nil, err)
err = gz.Close()
utils.AssertEqual(t, nil, err)
c.Request().SetBody(b.Bytes())
utils.AssertEqual(t, []byte("john=doe"), c.Body())
}
// go test -v -run=^$ -bench=Benchmark_Ctx_Body_With_Compression -benchmem -count=4
func Benchmark_Ctx_Body_With_Compression(b *testing.B){
app := New()
c := app.AcquireCtx(&fasthttp.RequestCtx{})
defer app.ReleaseCtx(c)
c.Request().Header.Set("Content-Encoding", "gzip")
var buf bytes.Buffer
gz := gzip.NewWriter(&buf)
_, err := gz.Write([]byte("john=doe"))
utils.AssertEqual(b, nil, err)
err = gz.Flush()
utils.AssertEqual(b, nil, err)
err = gz.Close()
utils.AssertEqual(b, nil, err)
c.Request().SetBody(buf.Bytes())
for i := 0; i < b.N; i++{
_ = c.Body()
}
utils.AssertEqual(b, []byte("john=doe"), c.Body())
}
// go test -run Test_Ctx_BodyParser
func Test_Ctx_BodyParser(t *testing.T) {
t.Parallel()
@ -1633,6 +1677,7 @@ func Test_Ctx_Render(t *testing.T) {
utils.AssertEqual(t, false, err == nil)
}
type testTemplateEngine struct {
mu sync.Mutex
templates *template.Template
@ -2196,6 +2241,7 @@ func Benchmark_Ctx_BodyStreamWriter(b *testing.B) {
}
}
func Test_Ctx_String(t *testing.T) {
t.Parallel()

View File

@ -684,3 +684,11 @@ const (
NetworkTCP4 = "tcp4"
NetworkTCP6 = "tcp6"
)
//Compression types
const (
StrGzip = "gzip"
StrBr = "br"
StrDeflate = "deflate"
StrBrotli = "brotli"
)