Repository: gofiber/fiber
File: ctx.go (Go)

Code before:
	decoder.IgnoreUnknownKeys(parserConfig.IgnoreUnknownKeys)
	if parserConfig.SetAliasTag != "" {
		decoder.SetAliasTag(parserConfig.SetAliasTag)
	}
	for _, v := range parserConfig.ParserType {
		decoder.RegisterConverter(reflect.ValueOf(v.Customtype).Interface(), v.Converter)
	}
	decoder.ZeroEmpty(parserConfig.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/problem+json, application/xml, application/x-www-form-urlencoded, multipart/form-data
// If none of the content types above are matched, it will return a ErrUnprocessableEntity error
func (c *Ctx) BodyParser(out interface{}) error {
	// Get content-type
	ctype := utils.ToLower(c.app.getString(c.fasthttp.Request.Header.ContentType()))

	ctype = utils.ParseVendorSpecificContentType(ctype)

    var ctypeEnd int
    if ctypeEnd = strings.IndexByte(ctype, ';'); ctypeEnd == -1 {
      ctypeEnd = len(ctype)
    }
    isJSON := strings.HasSuffix(utils.TrimRight(ctype, ' '), "+json")

    // Parse body accordingly
	if strings.HasPrefix(ctype, MIMEApplicationJSON) || isJSON {
		return c.app.config.JSONDecoder(c.Body(), out)
	}
	if strings.HasPrefix(ctype, MIMEApplicationForm) {
		data := make(map[string][]string)
		var err error

		c.fasthttp.PostArgs().VisitAll(func(key, val []byte) {
			if err != nil {
				return
			}

			k := c.app.getString(key)
			v := c.app.getString(val)

			if strings.Contains(k, "[") {
				k, err = parseParamSquareBrackets(k)
			}

			if c.app.config.EnableSplittingOnParsers && strings.Contains(v, ",") && equalFieldType(out, reflect.Slice, k, bodyTag) {
				values := strings.Split(v, ",")
				for i := 0; i < len(values); i++ {
					data[k] = append(data[k], values[i])

Review comment (performance):
Wouldn't hasPrefix with "+json" and "/json" be enough?

is ctypeEnd unused ?

can you please share the benchmark numbers before this customization and after, so we can see how much more time or performance gain this customization has

Code after:
	decoder.IgnoreUnknownKeys(parserConfig.IgnoreUnknownKeys)
	if parserConfig.SetAliasTag != "" {
		decoder.SetAliasTag(parserConfig.SetAliasTag)
	}
	for _, v := range parserConfig.ParserType {
		decoder.RegisterConverter(reflect.ValueOf(v.Customtype).Interface(), v.Converter)
	}
	decoder.ZeroEmpty(parserConfig.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
// All JSON extenstion mime types are supported (eg. application/problem+json)
// If none of the content types above are matched, it will return a ErrUnprocessableEntity error
func (c *Ctx) BodyParser(out interface{}) error {
	// Get content-type
	ctype := utils.ToLower(c.app.getString(c.fasthttp.Request.Header.ContentType()))

	ctype = utils.ParseVendorSpecificContentType(ctype)

	// Only use ctype string up to and excluding byte ';'
	ctypeEnd := strings.IndexByte(ctype, ';')
	if ctypeEnd != -1 {
		ctype = ctype[:ctypeEnd]
	}

	// Parse body accordingly
	if strings.HasSuffix(ctype, "json") {
		return c.app.config.JSONDecoder(c.Body(), out)
	}
	if strings.HasPrefix(ctype, MIMEApplicationForm) {
		data := make(map[string][]string)
		var err error

		c.fasthttp.PostArgs().VisitAll(func(key, val []byte) {
			if err != nil {
				return
			}

			k := c.app.getString(key)
			v := c.app.getString(val)

			if strings.Contains(k, "[") {
				k, err = parseParamSquareBrackets(k)
			}

			if c.app.config.EnableSplittingOnParsers && strings.Contains(v, ",") && equalFieldType(out, reflect.Slice, k, bodyTag) {
				values := strings.Split(v, ",")
				for i := 0; i < len(values); i++ {