The open and composable observability and data visualization platform. Visualize metrics, logs, and traces from multiple sources like Prometheus, Loki, Elasticsearch, InfluxDB, Postgres and many more.
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.
 
 
 
 
 
 
grafana/pkg/registry/apis/provisioning/request.go

70 lines
2.1 KiB

package provisioning
import (
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
"strings"
)
const (
// contentTypeJSON is the Content-Type for JSON requests as go standard library does not provide one
contentTypeJSON = "application/json"
// defaultMaxBodySize is the default max size for request bodies (10KB)
defaultMaxBodySize = 10 * 1024
// errMsgRequestTooLarge is the error message for request bodies that are too large
errMsgRequestTooLarge = "request body too large"
)
// readBody reads the request body and limits the size
func readBody(r *http.Request, maxSize int64) ([]byte, error) {
limitedBody := http.MaxBytesReader(nil, r.Body, maxSize)
body, err := io.ReadAll(limitedBody)
if err != nil {
var maxBytesError *http.MaxBytesError
if errors.As(err, &maxBytesError) {
return nil, fmt.Errorf("%s: max size %d bytes", errMsgRequestTooLarge, maxSize)
}
return nil, fmt.Errorf("error reading request body: %w", err)
}
defer func() { _ = limitedBody.Close() }()
return body, nil
}
// isJSONContentType checks if the request has the JSON Content-Type
func isJSONContentType(r *http.Request) bool {
contentType := r.Header.Get("Content-Type")
return strings.HasPrefix(contentType, contentTypeJSON)
}
// unmarshalJSON unmarshals the request body into the provided interface
// it also checks the Content-Type and limits the size of the request body
func unmarshalJSON(r *http.Request, maxSize int64, v interface{}) error {
if !isJSONContentType(r) {
return fmt.Errorf("content type is not JSON: %s", r.Header.Get("Content-Type"))
}
r.Body = http.MaxBytesReader(nil, r.Body, maxSize)
decoder := json.NewDecoder(r.Body)
decoder.DisallowUnknownFields()
if err := decoder.Decode(v); err != nil {
var maxBytesError *http.MaxBytesError
if errors.As(err, &maxBytesError) {
return fmt.Errorf("%s: max size %d bytes", errMsgRequestTooLarge, maxSize)
}
if err == io.EOF {
return fmt.Errorf("empty request body")
}
return fmt.Errorf("error decoding JSON: %w", err)
}
if decoder.More() {
return fmt.Errorf("multiple JSON objects not allowed")
}
return nil
}