mirror of
https://github.com/gofiber/fiber.git
synced 2025-04-28 14:07:56 +00:00
🔥 Add function to override form decoder setting (#1100)
* 🔥 add function to overide form decoder setting 🔥 Feature : SetBodyParserDecoder map all option to form decoder, use with BodyParserConfig, BodyParserType 🚨 Test : Test_Ctx_BodyParser_WithSetBodyParserDecoder * 🔥 Use decoder builder function with default setting on init decoderPool
This commit is contained in:
parent
26c29e248f
commit
35e38db771
43
ctx.go
43
ctx.go
@ -86,6 +86,21 @@ type Views interface {
|
|||||||
Render(io.Writer, string, interface{}, ...string) error
|
Render(io.Writer, string, interface{}, ...string) error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BodyParserType require two element, type and converter for register.
|
||||||
|
// Use BodyParserType with BodyParser for parsing custom type in form data.
|
||||||
|
type BodyParserType struct {
|
||||||
|
Customtype interface{}
|
||||||
|
Converter func(string) reflect.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
// BodyParserConfig form decoder config for SetBodyParserDecoder
|
||||||
|
type BodyParserConfig struct {
|
||||||
|
IgnoreUnknownKeys bool
|
||||||
|
SetAliasTag string
|
||||||
|
BodyParserType []BodyParserType
|
||||||
|
ZeroEmpty bool
|
||||||
|
}
|
||||||
|
|
||||||
// AcquireCtx retrieves a new Ctx from the pool.
|
// AcquireCtx retrieves a new Ctx from the pool.
|
||||||
func (app *App) AcquireCtx(fctx *fasthttp.RequestCtx) *Ctx {
|
func (app *App) AcquireCtx(fctx *fasthttp.RequestCtx) *Ctx {
|
||||||
c := app.pool.Get().(*Ctx)
|
c := app.pool.Get().(*Ctx)
|
||||||
@ -272,12 +287,32 @@ func (c *Ctx) Body() []byte {
|
|||||||
|
|
||||||
// decoderPool helps to improve BodyParser's and QueryParser's performance
|
// decoderPool helps to improve BodyParser's and QueryParser's performance
|
||||||
var decoderPool = &sync.Pool{New: func() interface{} {
|
var decoderPool = &sync.Pool{New: func() interface{} {
|
||||||
var decoder = schema.NewDecoder()
|
return decoderBuilder(BodyParserConfig{
|
||||||
decoder.ZeroEmpty(true)
|
IgnoreUnknownKeys: true,
|
||||||
decoder.IgnoreUnknownKeys(true)
|
ZeroEmpty: true,
|
||||||
return decoder
|
})
|
||||||
}}
|
}}
|
||||||
|
|
||||||
|
// SetBodyParserDecoder allow globally change the option of form decoder, update decoderPool
|
||||||
|
func SetBodyParserDecoder(bodyParserConfig BodyParserConfig) {
|
||||||
|
decoderPool = &sync.Pool{New: func() interface{} {
|
||||||
|
return decoderBuilder(bodyParserConfig)
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
|
func decoderBuilder(bodyParserConfig BodyParserConfig) interface{} {
|
||||||
|
var decoder = schema.NewDecoder()
|
||||||
|
decoder.IgnoreUnknownKeys(bodyParserConfig.IgnoreUnknownKeys)
|
||||||
|
if bodyParserConfig.SetAliasTag != "" {
|
||||||
|
decoder.SetAliasTag(bodyParserConfig.SetAliasTag)
|
||||||
|
}
|
||||||
|
for _, v := range bodyParserConfig.BodyParserType {
|
||||||
|
decoder.RegisterConverter(reflect.ValueOf(v.Customtype).Interface(), v.Converter)
|
||||||
|
}
|
||||||
|
decoder.ZeroEmpty(bodyParserConfig.ZeroEmpty)
|
||||||
|
return decoder
|
||||||
|
}
|
||||||
|
|
||||||
// BodyParser binds the request body to a struct.
|
// BodyParser binds the request body to a struct.
|
||||||
// It supports decoding the following content types based on the Content-Type header:
|
// It supports decoding the following content types based on the Content-Type header:
|
||||||
// application/json, application/xml, application/x-www-form-urlencoded, multipart/form-data
|
// application/json, application/xml, application/x-www-form-urlencoded, multipart/form-data
|
||||||
|
54
ctx_test.go
54
ctx_test.go
@ -399,6 +399,60 @@ func Test_Ctx_BodyParser(t *testing.T) {
|
|||||||
testDecodeParserError(MIMEMultipartForm+`;boundary="b"`, "--b")
|
testDecodeParserError(MIMEMultipartForm+`;boundary="b"`, "--b")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// go test -run Test_Ctx_BodyParser_WithSetBodyParserDecoder
|
||||||
|
func Test_Ctx_BodyParser_WithSetBodyParserDecoder(t *testing.T) {
|
||||||
|
type CustomTime time.Time
|
||||||
|
|
||||||
|
var timeConverter = func(value string) reflect.Value {
|
||||||
|
if v, err := time.Parse("2006-01-02", value); err == nil {
|
||||||
|
return reflect.ValueOf(v)
|
||||||
|
}
|
||||||
|
return reflect.Value{}
|
||||||
|
}
|
||||||
|
|
||||||
|
customTime := BodyParserType{
|
||||||
|
Customtype: CustomTime{},
|
||||||
|
Converter: timeConverter,
|
||||||
|
}
|
||||||
|
|
||||||
|
SetBodyParserDecoder(BodyParserConfig{
|
||||||
|
IgnoreUnknownKeys: true,
|
||||||
|
BodyParserType: []BodyParserType{customTime},
|
||||||
|
ZeroEmpty: true,
|
||||||
|
SetAliasTag: "form",
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Parallel()
|
||||||
|
app := New()
|
||||||
|
c := app.AcquireCtx(&fasthttp.RequestCtx{})
|
||||||
|
defer app.ReleaseCtx(c)
|
||||||
|
|
||||||
|
type Demo struct {
|
||||||
|
Date CustomTime `form:"date"`
|
||||||
|
Title string `form:"title"`
|
||||||
|
Body string `form:"body"`
|
||||||
|
}
|
||||||
|
|
||||||
|
testDecodeParser := func(contentType, body string) {
|
||||||
|
c.Request().Header.SetContentType(contentType)
|
||||||
|
c.Request().SetBody([]byte(body))
|
||||||
|
c.Request().Header.SetContentLength(len(body))
|
||||||
|
d := Demo{
|
||||||
|
Title: "Existing title",
|
||||||
|
Body: "Existing Body",
|
||||||
|
}
|
||||||
|
utils.AssertEqual(t, nil, c.BodyParser(&d))
|
||||||
|
date := fmt.Sprintf("%v", d.Date)
|
||||||
|
fmt.Println(date, d.Title, d.Body)
|
||||||
|
utils.AssertEqual(t, "{0 63743587200 <nil>}", date)
|
||||||
|
utils.AssertEqual(t, "", d.Title)
|
||||||
|
utils.AssertEqual(t, "New Body", d.Body)
|
||||||
|
}
|
||||||
|
|
||||||
|
testDecodeParser(MIMEApplicationForm, "date=2020-12-15&title=&body=New Body")
|
||||||
|
testDecodeParser(MIMEMultipartForm+`; boundary="b"`, "--b\r\nContent-Disposition: form-data; name=\"date\"\r\n\r\n2020-12-15\r\n--b\r\nContent-Disposition: form-data; name=\"title\"\r\n\r\n\r\n--b\r\nContent-Disposition: form-data; name=\"body\"\r\n\r\nNew Body\r\n--b--")
|
||||||
|
}
|
||||||
|
|
||||||
// go test -v -run=^$ -bench=Benchmark_Ctx_BodyParser_JSON -benchmem -count=4
|
// go test -v -run=^$ -bench=Benchmark_Ctx_BodyParser_JSON -benchmem -count=4
|
||||||
func Benchmark_Ctx_BodyParser_JSON(b *testing.B) {
|
func Benchmark_Ctx_BodyParser_JSON(b *testing.B) {
|
||||||
app := New()
|
app := New()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user