diff --git a/lang/lang_test.go b/lang/lang_test.go index a07030e5..e4569f93 100644 --- a/lang/lang_test.go +++ b/lang/lang_test.go @@ -171,6 +171,7 @@ func (suite *LangTestSuite) TestDetectLanguage() { suite.Equal(l.languages["en-US"], l.DetectLanguage("en, fr-FR;q=0.9")) suite.Equal(l.languages["en-US"], l.DetectLanguage("*")) suite.Equal(l.languages["en-US"], l.DetectLanguage("notalang")) + suite.Equal(l.languages["en-US"], l.DetectLanguage("")) } func (suite *LangTestSuite) TestLanguagesGet() { diff --git a/log/log_bench_test.go b/log/log_bench_test.go new file mode 100644 index 00000000..b8d624d8 --- /dev/null +++ b/log/log_bench_test.go @@ -0,0 +1,34 @@ +package log + +import ( + "io" + "net/http" + "net/http/httptest" + "testing" + + "goyave.dev/goyave/v5" + "goyave.dev/goyave/v5/config" + "goyave.dev/goyave/v5/slog" +) + +func BenchmarkServeHTTPWithLogs(b *testing.B) { + cfg := config.LoadDefault() + cfg.Set("app.debug", false) + logger := slog.New(slog.NewHandler(false, io.Discard)) + s, _ := goyave.New(goyave.Options{Config: cfg, Logger: logger}) + + s.RegisterRoutes(func(_ *goyave.Server, r *goyave.Router) { + r.GlobalMiddleware(CombinedLogMiddleware()) + r.Get("/user/{id}", func(r *goyave.Response, req *goyave.Request) { + r.String(http.StatusOK, req.RouteParams["id"]) + }) + }) + + req := httptest.NewRequest(http.MethodGet, "/user/1", nil) + + b.ReportAllocs() + b.ResetTimer() + for n := 0; n < b.N; n++ { + s.Router().ServeHTTP(httptest.NewRecorder(), req) + } +} diff --git a/middleware/compress/compress.go b/middleware/compress/compress.go index 3b63eb21..34632572 100644 --- a/middleware/compress/compress.go +++ b/middleware/compress/compress.go @@ -146,6 +146,9 @@ func (m *Middleware) getEncoder(response *goyave.Response, request *goyave.Reque return nil } acceptedEncodings := httputil.ParseMultiValuesHeader(request.Header().Get("Accept-Encoding")) + if len(acceptedEncodings) == 0 { + return nil + } groupedByPriority := lo.PartitionBy(acceptedEncodings, func(h httputil.HeaderValue) float64 { return h.Priority }) diff --git a/middleware/compress/compress_test.go b/middleware/compress/compress_test.go index e2736f2f..12b68c4b 100644 --- a/middleware/compress/compress_test.go +++ b/middleware/compress/compress_test.go @@ -293,6 +293,11 @@ func TestEncoderPriority(t *testing.T) { acceptEncoding: "gzip;q=0.8, *;q=1.0", want: br, }, + { + encoders: []Encoder{br, zstd, gzip}, + acceptEncoding: "", + want: nil, + }, } for _, c := range cases { diff --git a/util/httputil/httputil.go b/util/httputil/httputil.go index ba4b300a..f49803f7 100644 --- a/util/httputil/httputil.go +++ b/util/httputil/httputil.go @@ -20,6 +20,8 @@ var qualityValueRegex = regexp.MustCompile(`^q=([01]\.[0-9]{1,3})$`) // quality values into account. The result is a slice of values sorted // according to the order of priority. // +// The input is trimmed. If the input is empty, returns an empty slice. +// // See: https://developer.mozilla.org/en-US/docs/Glossary/Quality_values // // For the following header: @@ -30,10 +32,19 @@ var qualityValueRegex = regexp.MustCompile(`^q=([01]\.[0-9]{1,3})$`) // // [{text/html 1} {*/* 0.7} {text/* 0.5}] func ParseMultiValuesHeader(header string) []HeaderValue { - split := strings.Split(header, ",") - values := make([]HeaderValue, 0, len(split)) + count := strings.Count(header, ",") + values := make([]HeaderValue, 0, count+1) - for _, v := range split { + h := strings.TrimSpace(header) + if h == "" { + return values + } + for { + comma := strings.Index(h, ",") + if comma == -1 { + comma = len(h) + } + v := h[:comma] val := HeaderValue{} if i := strings.Index(v, ";"); i != -1 { // Parse priority @@ -49,13 +60,17 @@ func ParseMultiValuesHeader(header string) []HeaderValue { // Priority set to 0 if the quality value cannot be parsed val.Priority = priority - val.Value = strings.Trim(v[:i], " ") + val.Value = strings.TrimSpace(v[:i]) } else { - val.Value = strings.Trim(v, " ") + val.Value = strings.TrimSpace(v) val.Priority = 1 } values = append(values, val) + if comma == len(h) { + break + } + h = h[comma+1:] } sort.Sort(byPriority(values)) diff --git a/util/httputil/httputil_test.go b/util/httputil/httputil_test.go index abd6ac34..9006cf1d 100644 --- a/util/httputil/httputil_test.go +++ b/util/httputil/httputil_test.go @@ -44,4 +44,12 @@ func TestParseMultiValuesHeader(t *testing.T) { expected = []HeaderValue{{Value: "fr", Priority: 0.3}} result = ParseMultiValuesHeader("fr;q=0.3") assert.Equal(t, expected, result) + + expected = []HeaderValue{} + result = ParseMultiValuesHeader("") + assert.Equal(t, expected, result) + + expected = []HeaderValue{} + result = ParseMultiValuesHeader(" ") + assert.Equal(t, expected, result) }