AFAIRE
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

101 lines
3.2 KiB

/*
------------------------------------------------------------------------------------------------------------------------
####### kong ####### Copyright (c) 2021-2022 losyme ################################################ MIT License #######
------------------------------------------------------------------------------------------------------------------------
*/
package decode
import (
"encoding/json"
"errors"
"fmt"
"io"
"mime"
"net/http"
"strings"
"forge.chapril.org/losyme/kong/context"
)
const _jsonMediaType = "application/json"
func JSON(c *context.Context, maxBodySize int64, v interface{}) error {
ct := c.Request.Header.Get("Content-Type")
if ct == "" {
return c.NewError(http.StatusUnsupportedMediaType, "header content type cannot be empty") //////////////////////
}
mt, _, err := mime.ParseMediaType(ct)
if err != nil || mt != _jsonMediaType {
return c.NewError( /////////////////////////////////////////////////////////////////////////////////////////////
http.StatusUnsupportedMediaType,
fmt.Sprintf("header content type must be %s not %s", _jsonMediaType, ct),
)
}
decoder := json.NewDecoder(http.MaxBytesReader(c.Response, c.Request.Body, maxBodySize))
decoder.DisallowUnknownFields()
if err := decoder.Decode(v); err != nil {
var (
jse *json.SyntaxError
jute *json.UnmarshalTypeError
)
switch {
case errors.As(err, &jse):
return c.NewError( /////////////////////////////////////////////////////////////////////////////////////////
http.StatusBadRequest,
fmt.Sprintf("request body contains badly-formed JSON (at position %d)", jse.Offset),
)
case errors.Is(err, io.ErrUnexpectedEOF):
return c.NewError(http.StatusBadRequest, "request body contains badly-formed JSON") ////////////////////////
case errors.As(err, &jute):
return c.NewError( /////////////////////////////////////////////////////////////////////////////////////////
http.StatusBadRequest,
fmt.Sprintf(
"request body contains an invalid value for the %q field (at position %d)",
jute.Field,
jute.Offset,
),
)
case strings.HasPrefix(err.Error(), "json: unknown field"):
return c.NewError( /////////////////////////////////////////////////////////////////////////////////////////
http.StatusBadRequest,
fmt.Sprintf(
"request body contains unknown field %s",
strings.TrimPrefix(err.Error(), "json: unknown field "),
),
)
case errors.Is(err, io.EOF):
return c.NewError(http.StatusBadRequest, "request body must not be empty") /////////////////////////////////
case err.Error() == "http: request body too large":
return c.NewError( /////////////////////////////////////////////////////////////////////////////////////////
http.StatusRequestEntityTooLarge,
fmt.Sprintf("request body must not be larger than %d bytes", maxBodySize),
)
default:
return err
}
}
if err := decoder.Decode(&struct{}{}); err != io.EOF {
return c.NewError( /////////////////////////////////////////////////////////////////////////////////////////////
http.StatusBadRequest,
"request body must only contain a single JSON object",
)
}
return nil
}
/*
######################################################################################################## @(°_°)@ #######
*/