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
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 |
|
} |
|
|
|
/* |
|
######################################################################################################## @(°_°)@ ####### |
|
*/
|
|
|