libhttp/accepts.go

73 lines
1.4 KiB
Go

package libhttp
import (
"fmt"
"net/http"
"strconv"
"strings"
"github.com/gobwas/glob"
"go.opentelemetry.io/otel/trace"
)
func Accepts(r *http.Request, defaultAccept string, validAccepts ...string) (string, int, error) {
_, t := tracer.Start(r.Context(), "Accepts", trace.WithSpanKind(trace.SpanKindInternal))
defer t.End()
accept := r.Header.Get(HeaderAccept)
if accept == "" {
return defaultAccept, http.StatusOK, nil
}
types := strings.Split(accept, ",")
mime := ""
acceptList := make([]string, len(types))
q := float64(0)
for i, t := range types {
params := strings.Split(t, ";")
foundMime := strings.TrimSpace(params[0])
acceptList[i] = foundMime
foundQ, err := findQ(params)
if err != nil {
return "", http.StatusBadRequest, ErrMalformedAccept
}
g, err := glob.Compile(foundMime)
if err != nil {
return "", http.StatusBadRequest, ErrMalformedAccept
}
for _, a := range validAccepts {
if g.Match(a) {
if foundQ > q {
mime = a
}
}
}
}
if mime == "" {
return "", http.StatusNotAcceptable, fmt.Errorf("media-type %s unsupported", strings.Join(acceptList, ", "))
}
return mime, 0, nil
}
func findQ(a []string) (float64, error) {
if len(a) == 1 {
return 1.0, nil
}
for i := 1; i < len(a); i++ {
parts := strings.Split(strings.TrimSpace(a[i]), "=")
if len(parts) == 2 && parts[0] == "q" {
return strconv.ParseFloat(parts[1], 64)
}
}
return 1.0, nil
}