mirror of https://github.com/gofiber/fiber.git
make content-type checking optional
parent
9887ac5979
commit
c8bc2e44ca
|
@ -109,9 +109,10 @@ you need.
|
|||
|
||||
### Parse Request Body
|
||||
|
||||
you can call `ctx.BodyJSON(v any) error` or `BodyXML(v any) error`
|
||||
you can call `Bind().JSON(v any)` / `Bind().XML(v any)` / `Bind().Form(v any)` / `Bind().Multipart(v any)`
|
||||
to unmarshal request Body.
|
||||
|
||||
These methods will check content-type HTTP header and call configured JSON or XML decoder to unmarshal.
|
||||
use `Bind().Strict()` to enable content-type checking.
|
||||
|
||||
```golang
|
||||
package main
|
||||
|
@ -127,13 +128,21 @@ type Body struct {
|
|||
func main() {
|
||||
app := fiber.New()
|
||||
|
||||
app.Get("/:id", func(c fiber.Ctx) error {
|
||||
app.Get("/", func(c fiber.Ctx) error {
|
||||
var data Body
|
||||
if err := c.Bind().JSON(&data).Err(); err != nil {
|
||||
return err
|
||||
}
|
||||
return c.JSON(data)
|
||||
})
|
||||
|
||||
app.Get("/strict", func(c fiber.Ctx) error {
|
||||
var data Body
|
||||
if err := c.Bind().Strict().JSON(&data).Err(); err != nil {
|
||||
return err
|
||||
}
|
||||
return c.JSON(data)
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
|
|
71
binder.go
71
binder.go
|
@ -15,9 +15,10 @@ var binderPool = sync.Pool{New: func() any {
|
|||
}}
|
||||
|
||||
type Bind struct {
|
||||
err error
|
||||
ctx Ctx
|
||||
val any // last decoded val
|
||||
err error
|
||||
ctx Ctx
|
||||
val any // last decoded val
|
||||
strict bool
|
||||
}
|
||||
|
||||
func (c *DefaultCtx) Bind() *Bind {
|
||||
|
@ -26,27 +27,37 @@ func (c *DefaultCtx) Bind() *Bind {
|
|||
return b
|
||||
}
|
||||
|
||||
func (b *Bind) setErr(err error) *Bind {
|
||||
b.err = err
|
||||
func (b *Bind) Strict() *Bind {
|
||||
b.strict = true
|
||||
return b
|
||||
}
|
||||
|
||||
func (b *Bind) HTTPErr() error {
|
||||
if b.err != nil {
|
||||
if fe, ok := b.err.(*Error); ok {
|
||||
return fe
|
||||
}
|
||||
|
||||
return NewError(http.StatusBadRequest, b.err.Error())
|
||||
}
|
||||
|
||||
return nil
|
||||
func (b *Bind) setErr(err error) *Bind {
|
||||
b.err = err
|
||||
return b
|
||||
}
|
||||
|
||||
func (b *Bind) reset() {
|
||||
b.ctx = nil
|
||||
b.val = nil
|
||||
b.err = nil
|
||||
b.strict = false
|
||||
}
|
||||
|
||||
// HTTPErr return a wrapped fiber.Error for 400 http bad request.
|
||||
// it's not safe to use after HTTPErr is called.
|
||||
func (b *Bind) HTTPErr() error {
|
||||
err := b.Err()
|
||||
|
||||
if err != nil {
|
||||
if fe, ok := err.(*Error); ok {
|
||||
return fe
|
||||
}
|
||||
|
||||
return NewError(http.StatusBadRequest, err.Error())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Err return binding error and put binder back to pool
|
||||
|
@ -61,17 +72,18 @@ func (b *Bind) Err() error {
|
|||
}
|
||||
|
||||
// JSON unmarshal body as json
|
||||
// unlike `ctx.BodyJSON`, this will also check "content-type" HTTP header.
|
||||
func (b *Bind) JSON(v any) *Bind {
|
||||
if b.err != nil {
|
||||
return b
|
||||
}
|
||||
|
||||
if !bytes.HasPrefix(b.ctx.Request().Header.ContentType(), utils.UnsafeBytes(MIMEApplicationJSON)) {
|
||||
return b.setErr(NewError(http.StatusUnsupportedMediaType, "expecting content-type \"application/json\""))
|
||||
if b.strict {
|
||||
if !bytes.HasPrefix(b.ctx.Request().Header.ContentType(), utils.UnsafeBytes(MIMEApplicationJSON)) {
|
||||
return b.setErr(NewError(http.StatusUnsupportedMediaType, "expecting content-type \"application/json\""))
|
||||
}
|
||||
}
|
||||
|
||||
if err := b.ctx.BodyJSON(v); err != nil {
|
||||
if err := b.ctx.App().config.JSONDecoder(b.ctx.Body(), v); err != nil {
|
||||
return b.setErr(err)
|
||||
}
|
||||
|
||||
|
@ -80,17 +92,18 @@ func (b *Bind) JSON(v any) *Bind {
|
|||
}
|
||||
|
||||
// XML unmarshal body as xml
|
||||
// unlike `ctx.BodyXML`, this will also check "content-type" HTTP header.
|
||||
func (b *Bind) XML(v any) *Bind {
|
||||
if b.err != nil {
|
||||
return b
|
||||
}
|
||||
|
||||
if !bytes.HasPrefix(b.ctx.Request().Header.ContentType(), utils.UnsafeBytes(MIMEApplicationXML)) {
|
||||
return b.setErr(NewError(http.StatusUnsupportedMediaType, "expecting content-type \"application/xml\""))
|
||||
if b.strict {
|
||||
if !bytes.HasPrefix(b.ctx.Request().Header.ContentType(), utils.UnsafeBytes(MIMEApplicationXML)) {
|
||||
return b.setErr(NewError(http.StatusUnsupportedMediaType, "expecting content-type \"application/xml\""))
|
||||
}
|
||||
}
|
||||
|
||||
if err := b.ctx.BodyXML(v); err != nil {
|
||||
if err := b.ctx.App().config.XMLDecoder(b.ctx.Body(), v); err != nil {
|
||||
return b.setErr(err)
|
||||
}
|
||||
|
||||
|
@ -104,8 +117,10 @@ func (b *Bind) Form(v any) *Bind {
|
|||
return b
|
||||
}
|
||||
|
||||
if !bytes.HasPrefix(b.ctx.Request().Header.ContentType(), utils.UnsafeBytes(MIMEApplicationForm)) {
|
||||
return b.setErr(NewError(http.StatusUnsupportedMediaType, "expecting content-type \"application/x-www-form-urlencoded\""))
|
||||
if b.strict {
|
||||
if !bytes.HasPrefix(b.ctx.Request().Header.ContentType(), utils.UnsafeBytes(MIMEApplicationForm)) {
|
||||
return b.setErr(NewError(http.StatusUnsupportedMediaType, "expecting content-type \"application/x-www-form-urlencoded\""))
|
||||
}
|
||||
}
|
||||
|
||||
if err := b.formDecode(v); err != nil {
|
||||
|
@ -123,8 +138,10 @@ func (b *Bind) Multipart(v any) *Bind {
|
|||
return b
|
||||
}
|
||||
|
||||
if !bytes.HasPrefix(b.ctx.Request().Header.ContentType(), utils.UnsafeBytes(MIMEMultipartForm)) {
|
||||
return b.setErr(NewError(http.StatusUnsupportedMediaType, "expecting content-type \"multipart/form-data\""))
|
||||
if b.strict {
|
||||
if !bytes.HasPrefix(b.ctx.Request().Header.ContentType(), utils.UnsafeBytes(MIMEMultipartForm)) {
|
||||
return b.setErr(NewError(http.StatusUnsupportedMediaType, "expecting content-type \"multipart/form-data\""))
|
||||
}
|
||||
}
|
||||
|
||||
if err := b.multipartDecode(v); err != nil {
|
||||
|
|
8
ctx.go
8
ctx.go
|
@ -260,14 +260,6 @@ func (c *DefaultCtx) Body() []byte {
|
|||
return body
|
||||
}
|
||||
|
||||
func (c *DefaultCtx) BodyJSON(v any) error {
|
||||
return c.app.config.JSONDecoder(c.Body(), v)
|
||||
}
|
||||
|
||||
func (c *DefaultCtx) BodyXML(v any) error {
|
||||
return c.app.config.XMLDecoder(c.Body(), v)
|
||||
}
|
||||
|
||||
// ClearCookie expires a specific cookie by key on the client side.
|
||||
// If no key is provided it expires all cookies that came with the request.
|
||||
func (c *DefaultCtx) ClearCookie(key ...string) {
|
||||
|
|
|
@ -58,12 +58,6 @@ type Ctx interface {
|
|||
// Make copies or use the Immutable setting instead.
|
||||
Body() []byte
|
||||
|
||||
// BodyJSON will unmarshal request body with Config.JSONDecoder
|
||||
BodyJSON(v any) error
|
||||
|
||||
// BodyXML will unmarshal request body with Config.XMLDecoder
|
||||
BodyXML(v any) error
|
||||
|
||||
// ClearCookie expires a specific cookie by key on the client side.
|
||||
// If no key is provided it expires all cookies that came with the request.
|
||||
ClearCookie(key ...string)
|
||||
|
|
Loading…
Reference in New Issue