From 13e7a7279094cf55a16109199ad1c1245b810062 Mon Sep 17 00:00:00 2001 From: Paramtamtam <7326800+tarampampam@users.noreply.github.com> Date: Fri, 28 Jan 2022 12:53:35 +0500 Subject: [PATCH] Fix for the X-Format header (#51) --- internal/breaker/os_signal_test.go | 4 -- internal/checkers/health_test.go | 4 -- internal/checkers/live_test.go | 2 - internal/cli/build/command_test.go | 2 - internal/cli/healthcheck/command_test.go | 2 - internal/cli/root_test.go | 10 --- internal/cli/serve/command_test.go | 2 - internal/cli/version/command_test.go | 4 -- internal/config/config_test.go | 4 -- internal/env/env_test.go | 2 - internal/http/common/middlewares_test.go | 2 - internal/http/core/formats.go | 68 +++++++++++++++---- internal/http/core/formats_test.go | 31 +++++---- .../http/handlers/errorpage/handler_test.go | 2 - .../http/handlers/healthz/handler_test.go | 2 - internal/http/handlers/index/handler_test.go | 2 - .../http/handlers/notfound/handler_test.go | 2 - .../http/handlers/version/handler_test.go | 2 - internal/http/server_test.go | 2 - internal/pick/picker_test.go | 8 --- internal/pick/strings_slice_test.go | 8 --- internal/tpl/properties_test.go | 2 - internal/tpl/render_test.go | 4 -- internal/version/version_test.go | 2 - test/hurl/x_code.hurl | 2 +- 25 files changed, 74 insertions(+), 101 deletions(-) diff --git a/internal/breaker/os_signal_test.go b/internal/breaker/os_signal_test.go index 26de81f..fc2fc29 100644 --- a/internal/breaker/os_signal_test.go +++ b/internal/breaker/os_signal_test.go @@ -12,8 +12,6 @@ import ( ) func TestNewOSSignals(t *testing.T) { - t.Parallel() - oss := breaker.NewOSSignals(context.Background()) gotSignal := make(chan os.Signal, 1) @@ -35,8 +33,6 @@ func TestNewOSSignals(t *testing.T) { } func TestNewOSSignalCtxCancel(t *testing.T) { - t.Parallel() - ctx, cancel := context.WithCancel(context.Background()) oss := breaker.NewOSSignals(ctx) diff --git a/internal/checkers/health_test.go b/internal/checkers/health_test.go index 2218af2..85bdb77 100644 --- a/internal/checkers/health_test.go +++ b/internal/checkers/health_test.go @@ -16,8 +16,6 @@ type httpClientFunc func(*http.Request) (*http.Response, error) func (f httpClientFunc) Do(req *http.Request) (*http.Response, error) { return f(req) } func TestHealthChecker_CheckSuccess(t *testing.T) { - t.Parallel() - var httpMock httpClientFunc = func(req *http.Request) (*http.Response, error) { assert.Equal(t, http.MethodGet, req.Method) assert.Equal(t, "http://127.0.0.1:123/healthz", req.URL.String()) @@ -35,8 +33,6 @@ func TestHealthChecker_CheckSuccess(t *testing.T) { } func TestHealthChecker_CheckFail(t *testing.T) { - t.Parallel() - var httpMock httpClientFunc = func(req *http.Request) (*http.Response, error) { return &http.Response{ Body: ioutil.NopCloser(bytes.NewReader([]byte{})), diff --git a/internal/checkers/live_test.go b/internal/checkers/live_test.go index 1b622e6..413d89b 100644 --- a/internal/checkers/live_test.go +++ b/internal/checkers/live_test.go @@ -8,7 +8,5 @@ import ( ) func TestLiveChecker_Check(t *testing.T) { - t.Parallel() - assert.NoError(t, checkers.NewLiveChecker().Check()) } diff --git a/internal/cli/build/command_test.go b/internal/cli/build/command_test.go index 9db3223..df9157a 100644 --- a/internal/cli/build/command_test.go +++ b/internal/cli/build/command_test.go @@ -3,7 +3,5 @@ package build_test import "testing" func TestNothing(t *testing.T) { - t.Parallel() - t.Skip("tests for this package have not been implemented yet") } diff --git a/internal/cli/healthcheck/command_test.go b/internal/cli/healthcheck/command_test.go index 0a12053..233aa90 100644 --- a/internal/cli/healthcheck/command_test.go +++ b/internal/cli/healthcheck/command_test.go @@ -16,8 +16,6 @@ type fakeChecker struct{ err error } func (c *fakeChecker) Check(port uint16) error { return c.err } func TestProperties(t *testing.T) { - t.Parallel() - cmd := healthcheck.NewCommand(&fakeChecker{err: nil}) assert.Equal(t, "healthcheck", cmd.Use) diff --git a/internal/cli/root_test.go b/internal/cli/root_test.go index 78398f6..e023fc6 100644 --- a/internal/cli/root_test.go +++ b/internal/cli/root_test.go @@ -9,8 +9,6 @@ import ( ) func TestSubcommands(t *testing.T) { - t.Parallel() - cmd := cli.NewCommand("unit test") cases := []struct { @@ -31,8 +29,6 @@ func TestSubcommands(t *testing.T) { for _, tt := range cases { tt := tt t.Run(tt.giveName, func(t *testing.T) { - t.Parallel() - if _, exists := subcommands[tt.giveName]; !exists { assert.Failf(t, "command not found", "command [%s] was not found", tt.giveName) } @@ -41,8 +37,6 @@ func TestSubcommands(t *testing.T) { } func TestFlags(t *testing.T) { - t.Parallel() - cmd := cli.NewCommand("unit test") cases := []struct { @@ -59,8 +53,6 @@ func TestFlags(t *testing.T) { for _, tt := range cases { tt := tt t.Run(tt.giveName, func(t *testing.T) { - t.Parallel() - flag := cmd.Flag(tt.giveName) if flag == nil { @@ -76,8 +68,6 @@ func TestFlags(t *testing.T) { } func TestExecuting(t *testing.T) { - t.Parallel() - cmd := cli.NewCommand("unit test") cmd.SetArgs([]string{}) diff --git a/internal/cli/serve/command_test.go b/internal/cli/serve/command_test.go index 8b48ee1..2882055 100644 --- a/internal/cli/serve/command_test.go +++ b/internal/cli/serve/command_test.go @@ -3,7 +3,5 @@ package serve_test import "testing" func TestNothing(t *testing.T) { - t.Parallel() - t.Skip("tests for this package have not been implemented yet") } diff --git a/internal/cli/version/command_test.go b/internal/cli/version/command_test.go index 98e95f4..27db5bc 100644 --- a/internal/cli/version/command_test.go +++ b/internal/cli/version/command_test.go @@ -10,8 +10,6 @@ import ( ) func TestProperties(t *testing.T) { - t.Parallel() - cmd := version.NewCommand("") assert.Equal(t, "version", cmd.Use) @@ -20,8 +18,6 @@ func TestProperties(t *testing.T) { } func TestCommandRun(t *testing.T) { - t.Parallel() - cmd := version.NewCommand("1.2.3@foobar") cmd.SetArgs([]string{}) diff --git a/internal/config/config_test.go b/internal/config/config_test.go index 2dda2c7..131b202 100644 --- a/internal/config/config_test.go +++ b/internal/config/config_test.go @@ -9,8 +9,6 @@ import ( ) func TestFromYaml(t *testing.T) { - t.Parallel() - var cases = map[string]struct { //nolint:maligned giveYaml []byte giveEnv map[string]string @@ -111,8 +109,6 @@ pages: for name, tt := range cases { t.Run(name, func(t *testing.T) { - t.Parallel() - if tt.giveEnv != nil { for key, value := range tt.giveEnv { assert.NoError(t, os.Setenv(key, value)) diff --git a/internal/env/env_test.go b/internal/env/env_test.go index 192b648..a97dd7c 100644 --- a/internal/env/env_test.go +++ b/internal/env/env_test.go @@ -8,8 +8,6 @@ import ( ) func TestConstants(t *testing.T) { - t.Parallel() - assert.Equal(t, "LISTEN_ADDR", string(ListenAddr)) assert.Equal(t, "LISTEN_PORT", string(ListenPort)) assert.Equal(t, "TEMPLATE_NAME", string(TemplateName)) diff --git a/internal/http/common/middlewares_test.go b/internal/http/common/middlewares_test.go index 7b2a699..f65e6b8 100644 --- a/internal/http/common/middlewares_test.go +++ b/internal/http/common/middlewares_test.go @@ -3,7 +3,5 @@ package common_test import "testing" func TestNothing2(t *testing.T) { - t.Parallel() - t.Skip("tests for this package have not been implemented yet") } diff --git a/internal/http/core/formats.go b/internal/http/core/formats.go index c7e2b15..e592c04 100644 --- a/internal/http/core/formats.go +++ b/internal/http/core/formats.go @@ -2,6 +2,8 @@ package core import ( "bytes" + "sort" + "strconv" "github.com/valyala/fasthttp" ) @@ -17,28 +19,66 @@ const ( ) func ClientWantFormat(ctx *fasthttp.RequestCtx) ContentType { - var ( - ct = bytes.ToLower(ctx.Request.Header.ContentType()) - f = bytes.ToLower(ctx.Request.Header.Peek(FormatHeader)) // for the Ingress support - ) + // parse "Content-Type" header (e.g.: `application/json;charset=UTF-8`) + if ct := bytes.ToLower(ctx.Request.Header.ContentType()); len(ct) > 4 { //nolint:gomnd + return mimeTypeToContentType(ct) + } + // parse `X-Format` header (aka `Accept`) for the Ingress support + // e.g.: `text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8` + if h := bytes.ToLower(bytes.TrimSpace(ctx.Request.Header.Peek(FormatHeader))); len(h) > 2 { //nolint:gomnd,nestif + type format struct { + mimeType []byte + weight float32 + } + + var formats = make([]format, 0, 8) //nolint:gomnd + + for _, b := range bytes.FieldsFunc(h, func(r rune) bool { return r == ',' }) { + if idx := bytes.Index(b, []byte(";q=")); idx > 0 && idx < len(b) { + f := format{b[0:idx], 0} + + if len(b) > idx+3 { + if weight, err := strconv.ParseFloat(string(b[idx+3:]), 32); err == nil { //nolint:gomnd + f.weight = float32(weight) + } + } + + formats = append(formats, f) + } else { + formats = append(formats, format{b, 1}) + } + } + + switch l := len(formats); { + case l == 0: + return UnknownContentType + + case l == 1: + return mimeTypeToContentType(formats[0].mimeType) + + default: + sort.SliceStable(formats, func(i, j int) bool { return formats[i].weight > formats[j].weight }) + + return mimeTypeToContentType(formats[0].mimeType) + } + } + + return UnknownContentType +} + +func mimeTypeToContentType(mimeType []byte) ContentType { switch { - case bytes.Contains(f, []byte("json")), - bytes.Contains(ct, []byte("application/json")), - bytes.Contains(ct, []byte("text/json")): + case bytes.Contains(mimeType, []byte("application/json")), bytes.Contains(mimeType, []byte("text/json")): return JSONContentType - case bytes.Contains(f, []byte("xml")), - bytes.Contains(ct, []byte("application/xml")), - bytes.Contains(ct, []byte("text/xml")): + case bytes.Contains(mimeType, []byte("application/xml")), bytes.Contains(mimeType, []byte("text/xml")): return XMLContentType - case bytes.Contains(f, []byte("html")), - bytes.Contains(ct, []byte("text/html")): + case bytes.Contains(mimeType, []byte("text/html")): return HTMLContentType - case bytes.Contains(f, []byte("plain")), - bytes.Contains(ct, []byte("text/plain")): + case bytes.Contains(mimeType, []byte("text/plain")): return PlainTextContentType } diff --git a/internal/http/core/formats_test.go b/internal/http/core/formats_test.go index f4a28d6..1237b8e 100644 --- a/internal/http/core/formats_test.go +++ b/internal/http/core/formats_test.go @@ -9,14 +9,26 @@ import ( ) func TestClientWantFormat(t *testing.T) { - t.Parallel() - for name, tt := range map[string]struct { giveContentTypeHeader string giveFormatHeader string giveReqCtx func() *fasthttp.RequestCtx wantFormat core.ContentType }{ + "priority": { + giveFormatHeader: "application/xml", + giveContentTypeHeader: "text/plain", + wantFormat: core.PlainTextContentType, + }, + "format respects weight": { + giveFormatHeader: "text/html;q=0.5,application/xhtml+xml;q=0.9,application/xml;q=1,*/*;q=0.8", + wantFormat: core.XMLContentType, + }, + "wrong format value": { + giveFormatHeader: ";q=foobar,bar/baz;;;;;application/xml", + wantFormat: core.UnknownContentType, + }, + "content type - application/json": { giveContentTypeHeader: "application/jsoN; charset=utf-8", wantFormat: core.JSONContentType, }, @@ -24,7 +36,7 @@ func TestClientWantFormat(t *testing.T) { giveContentTypeHeader: "text/Json; charset=utf-8", wantFormat: core.JSONContentType, }, "format - json": { - giveFormatHeader: "jsOn", wantFormat: core.JSONContentType, + giveFormatHeader: "application/jsoN,*/*;q=0.8", wantFormat: core.JSONContentType, }, "content type - application/xml": { @@ -34,21 +46,22 @@ func TestClientWantFormat(t *testing.T) { giveContentTypeHeader: "text/Xml; charset=utf-8", wantFormat: core.XMLContentType, }, "format - xml": { - giveFormatHeader: "xMl", wantFormat: core.XMLContentType, + giveFormatHeader: "text/Xml", wantFormat: core.XMLContentType, }, "content type - text/html": { giveContentTypeHeader: "text/htMl; charset=utf-8", wantFormat: core.HTMLContentType, }, "format - html": { - giveFormatHeader: "HtmL", wantFormat: core.HTMLContentType, + giveFormatHeader: "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8", + wantFormat: core.HTMLContentType, }, "content type - text/plain": { giveContentTypeHeader: "text/plaiN; charset=utf-8", wantFormat: core.PlainTextContentType, }, "format - plain": { - giveFormatHeader: "PLAIN", wantFormat: core.PlainTextContentType, + giveFormatHeader: "text/plaiN,text/html,application/xml;q=0.9,,,*/*;q=0.8", wantFormat: core.PlainTextContentType, }, "unknown on empty": { @@ -61,8 +74,6 @@ func TestClientWantFormat(t *testing.T) { }, } { t.Run(name, func(t *testing.T) { - t.Parallel() - h := &fasthttp.RequestHeader{} h.Set(fasthttp.HeaderContentType, tt.giveContentTypeHeader) h.Set(core.FormatHeader, tt.giveFormatHeader) @@ -79,8 +90,6 @@ func TestClientWantFormat(t *testing.T) { } func TestSetClientFormat(t *testing.T) { - t.Parallel() - for name, tt := range map[string]struct { giveContentType core.ContentType wantHeaderValue string @@ -92,8 +101,6 @@ func TestSetClientFormat(t *testing.T) { "plain": {giveContentType: core.PlainTextContentType, wantHeaderValue: "text/plain; charset=utf-8"}, } { t.Run(name, func(t *testing.T) { - t.Parallel() - ctx := &fasthttp.RequestCtx{ Response: fasthttp.Response{ Header: fasthttp.ResponseHeader{}, diff --git a/internal/http/handlers/errorpage/handler_test.go b/internal/http/handlers/errorpage/handler_test.go index a262578..5c974ff 100644 --- a/internal/http/handlers/errorpage/handler_test.go +++ b/internal/http/handlers/errorpage/handler_test.go @@ -3,7 +3,5 @@ package errorpage_test import "testing" func TestNothing(t *testing.T) { - t.Parallel() - t.Skip("tests for this package have not been implemented yet") } diff --git a/internal/http/handlers/healthz/handler_test.go b/internal/http/handlers/healthz/handler_test.go index 585e1d2..fbc25f2 100644 --- a/internal/http/handlers/healthz/handler_test.go +++ b/internal/http/handlers/healthz/handler_test.go @@ -3,7 +3,5 @@ package healthz_test import "testing" func TestNothing(t *testing.T) { - t.Parallel() - t.Skip("tests for this package have not been implemented yet") } diff --git a/internal/http/handlers/index/handler_test.go b/internal/http/handlers/index/handler_test.go index 4530471..4543537 100644 --- a/internal/http/handlers/index/handler_test.go +++ b/internal/http/handlers/index/handler_test.go @@ -3,7 +3,5 @@ package index_test import "testing" func TestNothing(t *testing.T) { - t.Parallel() - t.Skip("tests for this package have not been implemented yet") } diff --git a/internal/http/handlers/notfound/handler_test.go b/internal/http/handlers/notfound/handler_test.go index e0b7c0b..3daed4d 100644 --- a/internal/http/handlers/notfound/handler_test.go +++ b/internal/http/handlers/notfound/handler_test.go @@ -3,7 +3,5 @@ package notfound_test import "testing" func TestNothing(t *testing.T) { - t.Parallel() - t.Skip("tests for this package have not been implemented yet") } diff --git a/internal/http/handlers/version/handler_test.go b/internal/http/handlers/version/handler_test.go index 7014943..72c102b 100644 --- a/internal/http/handlers/version/handler_test.go +++ b/internal/http/handlers/version/handler_test.go @@ -3,7 +3,5 @@ package version_test import "testing" func TestNothing(t *testing.T) { - t.Parallel() - t.Skip("tests for this package have not been implemented yet") } diff --git a/internal/http/server_test.go b/internal/http/server_test.go index 5b4081f..66c2992 100644 --- a/internal/http/server_test.go +++ b/internal/http/server_test.go @@ -3,7 +3,5 @@ package http import "testing" func TestNothing(t *testing.T) { - t.Parallel() - t.Skip("tests for this package have not been implemented yet") } diff --git a/internal/pick/picker_test.go b/internal/pick/picker_test.go index abef747..12d7783 100644 --- a/internal/pick/picker_test.go +++ b/internal/pick/picker_test.go @@ -8,8 +8,6 @@ import ( ) func TestPicker_NextIndex_First(t *testing.T) { - t.Parallel() - for i := uint32(0); i < 100; i++ { p := pick.NewPicker(i, pick.First) @@ -20,8 +18,6 @@ func TestPicker_NextIndex_First(t *testing.T) { } func TestPicker_NextIndex_RandomOnce(t *testing.T) { - t.Parallel() - for i := uint8(0); i < 10; i++ { assert.Equal(t, uint32(0), pick.NewPicker(0, pick.RandomOnce).NextIndex()) } @@ -39,8 +35,6 @@ func TestPicker_NextIndex_RandomOnce(t *testing.T) { } func TestPicker_NextIndex_RandomEveryTime(t *testing.T) { - t.Parallel() - for i := uint8(0); i < 10; i++ { assert.Equal(t, uint32(0), pick.NewPicker(0, pick.RandomEveryTime).NextIndex()) } @@ -59,7 +53,5 @@ func TestPicker_NextIndex_RandomEveryTime(t *testing.T) { } func TestPicker_NextIndex_Unsupported(t *testing.T) { - t.Parallel() - assert.Panics(t, func() { pick.NewPicker(1, 255).NextIndex() }) } diff --git a/internal/pick/strings_slice_test.go b/internal/pick/strings_slice_test.go index 4b92ff7..baa2dca 100644 --- a/internal/pick/strings_slice_test.go +++ b/internal/pick/strings_slice_test.go @@ -8,11 +8,7 @@ import ( ) func TestStringsSlice_Pick(t *testing.T) { - t.Parallel() - t.Run("first", func(t *testing.T) { - t.Parallel() - for i := uint8(0); i < 100; i++ { assert.Equal(t, "", pick.NewStringsSlice([]string{}, pick.First).Pick()) } @@ -25,8 +21,6 @@ func TestStringsSlice_Pick(t *testing.T) { }) t.Run("random once", func(t *testing.T) { - t.Parallel() - for i := uint8(0); i < 100; i++ { assert.Equal(t, "", pick.NewStringsSlice([]string{}, pick.RandomOnce).Pick()) } @@ -42,8 +36,6 @@ func TestStringsSlice_Pick(t *testing.T) { }) t.Run("random every time", func(t *testing.T) { - t.Parallel() - for i := uint8(0); i < 100; i++ { assert.Equal(t, "", pick.NewStringsSlice([]string{}, pick.RandomEveryTime).Pick()) } diff --git a/internal/tpl/properties_test.go b/internal/tpl/properties_test.go index 4db033f..d2d1e2a 100644 --- a/internal/tpl/properties_test.go +++ b/internal/tpl/properties_test.go @@ -8,8 +8,6 @@ import ( ) func TestProperties_Replaces(t *testing.T) { - t.Parallel() - props := tpl.Properties{ Code: "foo", Message: "bar", diff --git a/internal/tpl/render_test.go b/internal/tpl/render_test.go index 82b7702..6f4d908 100644 --- a/internal/tpl/render_test.go +++ b/internal/tpl/render_test.go @@ -8,8 +8,6 @@ import ( ) func Test_Render(t *testing.T) { - t.Parallel() - for name, tt := range map[string]struct { giveContent string giveProps tpl.Properties @@ -54,8 +52,6 @@ func Test_Render(t *testing.T) { }, } { t.Run(name, func(t *testing.T) { - t.Parallel() - content, err := tpl.Render([]byte(tt.giveContent), tt.giveProps) if tt.wantError == true { diff --git a/internal/version/version_test.go b/internal/version/version_test.go index ade2466..bed3e5b 100644 --- a/internal/version/version_test.go +++ b/internal/version/version_test.go @@ -5,8 +5,6 @@ import ( ) func TestVersion(t *testing.T) { - t.Parallel() - for give, want := range map[string]string{ // without changes "vvv": "vvv", diff --git a/test/hurl/x_code.hurl b/test/hurl/x_code.hurl index 4529cb0..a0f0133 100644 --- a/test/hurl/x_code.hurl +++ b/test/hurl/x_code.hurl @@ -13,7 +13,7 @@ body contains "Gone" # X-Code with X-Format GET http://{{ host }}:{{ port }}/ X-Code: 410 -X-Format: text/json +X-Format: text/html;q=0.9,application/xhtml+xml;q=0.9,application/json,image/avif,image/webp,*/*;q=0.8 HTTP/* 410