Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

馃敟 Add function to override form decoder setting #1100

Merged
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
31 changes: 31 additions & 0 deletions ctx.go
Expand Up @@ -77,6 +77,21 @@ type Views interface {
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.
func (app *App) AcquireCtx(fctx *fasthttp.RequestCtx) *Ctx {
c := app.pool.Get().(*Ctx)
Expand Down Expand Up @@ -244,6 +259,22 @@ var decoderPool = &sync.Pool{New: func() interface{} {
return decoder
}}

// SetBodyParserDecoder allow globally change the option of form decoder, update decoderPool
func SetBodyParserDecoder(bodyParserConfig BodyParserConfig) {
Copy link
Member

Choose a reason for hiding this comment

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

can we use the method for the initial write of the decoder pool ?
https://github.com/gofiber/fiber/blob/master/ctx.go#L274
@rockcreation7

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sure, I can help update the doc on this, thanks.

Please feel free to let me know anything that can help.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

or you mean I put a change to the initial write?

Copy link
Member

Choose a reason for hiding this comment

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

or you mean I put a change to the initial write?

@rockcreation7
yes exactly, with the initial set you can also use your method or ?

will merge it directly after the adjustment

decoderPool = &sync.Pool{New: func() 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.
// 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
Expand Down
54 changes: 54 additions & 0 deletions ctx_test.go
Expand Up @@ -339,6 +339,60 @@ func Test_Ctx_BodyParser(t *testing.T) {
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
func Benchmark_Ctx_BodyParser_JSON(b *testing.B) {
app := New()
Expand Down