diff --git a/configuration/backend_test.go b/configuration/backend_test.go index a4f95b39..d549f719 100644 --- a/configuration/backend_test.go +++ b/configuration/backend_test.go @@ -385,6 +385,36 @@ func TestGetBackend(t *testing.T) { if b.Compression.Direction != "both" { t.Errorf("%v: Compression.Direction not both: %v", b.Name, b.Compression.Direction) } + if b.Compression.AlgoReq != "raw-deflate" { + t.Errorf("%v: Compression.AlgoReq wrong: %v", b.Name, b.Compression.AlgoReq) + } + if len(b.Compression.AlgosRes) != 2 { + t.Errorf("%v: len Compression.AlgosRes not 2: %v", b.Name, len(b.Compression.AlgosRes)) + } else { + if !(b.Compression.AlgosRes[0] == "identity" || b.Compression.AlgosRes[0] == "raw-deflate") { + t.Errorf("%v: Compression.AlgosRes[0] wrong: %v", b.Name, b.Compression.AlgosRes[0]) + } + if !(b.Compression.AlgosRes[1] != "identity" || b.Compression.AlgosRes[0] == "raw-deflate") { + t.Errorf("%v: Compression.AlgosRes[1] wrong: %v", b.Name, b.Compression.AlgosRes[1]) + } + } + if len(b.Compression.TypesReq) != 2 { + t.Errorf("%v: len Compression.TypesReq not 2: %v", b.Name, len(b.Compression.TypesReq)) + } else { + if !(b.Compression.TypesReq[0] == "text/plain" || b.Compression.TypesReq[0] == "application/json") { + t.Errorf("%v: Compression.TypesReq[0] wrong: %v", b.Name, b.Compression.TypesReq[0]) + } + if !(b.Compression.TypesReq[1] != "text/plain" || b.Compression.TypesReq[0] == "application/json") { + t.Errorf("%v: Compression.TypesReq[1] wrong: %v", b.Name, b.Compression.TypesReq[1]) + } + } + if len(b.Compression.TypesRes) != 1 { + t.Errorf("%v: len Compression.TypesRes not 1: %v", b.Name, len(b.Compression.TypesRes)) + } else { + if !(b.Compression.TypesReq[0] == "text/plain") { + t.Errorf("%v: Compression.TypesReq[0] wrong: %v", b.Name, b.Compression.TypesReq[0]) + } + } } if b.Checkcache != "enabled" { t.Errorf("%v: Checkcache not enabled: %v", b.Name, b.Checkcache) diff --git a/configuration/configuration.go b/configuration/configuration.go index 7e0969c9..7a9a649e 100644 --- a/configuration/configuration.go +++ b/configuration/configuration.go @@ -1146,7 +1146,7 @@ func (s *SectionParser) monitorFail() interface{} { return nil } -func (s *SectionParser) compression() interface{} { +func (s *SectionParser) compression() interface{} { //nolint:gocognit compressionFound := false compression := &models.Compression{} @@ -1160,6 +1160,24 @@ func (s *SectionParser) compression() interface{} { } } + data, err = s.get("compression algo-req", false) + if err == nil { + d, ok := data.(*types.StringC) + if ok && d != nil { + compressionFound = true + compression.AlgoReq = d.Value + } + } + + data, err = s.get("compression algo-res", false) + if err == nil { + d, ok := data.(*types.StringSliceC) + if ok && d != nil && len(d.Value) > 0 { + compressionFound = true + compression.AlgosRes = d.Value + } + } + data, err = s.get("compression type", false) if err == nil { d, ok := data.(*types.StringSliceC) @@ -1169,6 +1187,24 @@ func (s *SectionParser) compression() interface{} { } } + data, err = s.get("compression type-req", false) + if err == nil { + d, ok := data.(*types.StringSliceC) + if ok && d != nil && len(d.Value) > 0 { + compressionFound = true + compression.TypesReq = d.Value + } + } + + data, err = s.get("compression type-res", false) + if err == nil { + d, ok := data.(*types.StringSliceC) + if ok && d != nil && len(d.Value) > 0 { + compressionFound = true + compression.TypesRes = d.Value + } + } + data, err = s.get("compression offload", false) if err == nil { d, ok := data.(*types.Enabled) @@ -2606,17 +2642,33 @@ func (s *SectionObject) statsOptions(field reflect.Value) error { return s.set("stats", ss) } -func (s *SectionObject) compression(field reflect.Value) error { +func (s *SectionObject) compression(field reflect.Value) error { //nolint:gocognit var err error if valueIsNil(field) { err = s.set("compression algo", nil) if err != nil { return err } + err = s.set("compression algo-req", nil) + if err != nil { + return err + } + err = s.set("compression algo-res", nil) + if err != nil { + return err + } err = s.set("compression type", nil) if err != nil { return err } + err = s.set("compression type-req", nil) + if err != nil { + return err + } + err = s.set("compression type-res", nil) + if err != nil { + return err + } err = s.set("compression offload", nil) if err != nil { return err @@ -2644,12 +2696,36 @@ func (s *SectionObject) compression(field reflect.Value) error { return err } } + if len(compression.AlgoReq) > 0 { + err = s.set("compression algo-req", &types.StringC{Value: compression.AlgoReq}) + if err != nil { + return err + } + } + if len(compression.AlgosRes) > 0 { + err = s.set("compression algo-res", &types.StringSliceC{Value: compression.AlgosRes}) + if err != nil { + return err + } + } if len(compression.Types) > 0 { err = s.set("compression type", &types.StringSliceC{Value: compression.Types}) if err != nil { return err } } + if len(compression.TypesReq) > 0 { + err = s.set("compression type-req", &types.StringSliceC{Value: compression.TypesReq}) + if err != nil { + return err + } + } + if len(compression.TypesRes) > 0 { + err = s.set("compression type-res", &types.StringSliceC{Value: compression.TypesRes}) + if err != nil { + return err + } + } if compression.Offload { err = s.set("compression offload", &types.Enabled{}) if err != nil { diff --git a/configuration/configuration_test.go b/configuration/configuration_test.go index ad5f2a4a..8d2332f1 100644 --- a/configuration/configuration_test.go +++ b/configuration/configuration_test.go @@ -524,6 +524,10 @@ frontend test compression algo identity gzip compression type text/plain compression offload + compression algo-req raw-deflate + compression algo-res raw-deflate identity + compression type-req text/plain application/json + compression type-res text/plain clitcpka-cnt 10 clitcpka-idle 10s clitcpka-intvl 10 @@ -676,6 +680,10 @@ backend test no option h1-case-adjust-bogus-server compression type application/json text/plain compression direction both + compression algo-req raw-deflate + compression algo-res raw-deflate identity + compression type-req text/plain application/json + compression type-res text/plain srvtcpka-cnt 10 srvtcpka-idle 10s srvtcpka-intvl 10 diff --git a/configuration/frontend_test.go b/configuration/frontend_test.go index 2a474b36..4246fdf0 100644 --- a/configuration/frontend_test.go +++ b/configuration/frontend_test.go @@ -318,6 +318,36 @@ func TestGetFrontend(t *testing.T) { if !f.Compression.Offload { t.Errorf("%v: Compression.Offload wrong: %v", f.Name, f.Compression.Offload) } + if f.Compression.AlgoReq != "raw-deflate" { + t.Errorf("%v: Compression.AlgoReq wrong: %v", f.Name, f.Compression.AlgoReq) + } + if len(f.Compression.AlgosRes) != 2 { + t.Errorf("%v: len Compression.AlgosRes not 2: %v", f.Name, len(f.Compression.AlgosRes)) + } else { + if !(f.Compression.AlgosRes[0] == "identity" || f.Compression.AlgosRes[0] == "raw-deflate") { + t.Errorf("%v: Compression.AlgosRes[0] wrong: %v", f.Name, f.Compression.AlgosRes[0]) + } + if !(f.Compression.AlgosRes[1] != "identity" || f.Compression.AlgosRes[0] == "raw-deflate") { + t.Errorf("%v: Compression.AlgosRes[1] wrong: %v", f.Name, f.Compression.AlgosRes[1]) + } + } + if len(f.Compression.TypesReq) != 2 { + t.Errorf("%v: len Compression.TypesReq not 2: %v", f.Name, len(f.Compression.TypesReq)) + } else { + if !(f.Compression.TypesReq[0] == "text/plain" || f.Compression.TypesReq[0] == "application/json") { + t.Errorf("%v: Compression.TypesReq[0] wrong: %v", f.Name, f.Compression.TypesReq[0]) + } + if !(f.Compression.TypesReq[1] != "text/plain" || f.Compression.TypesReq[0] == "application/json") { + t.Errorf("%v: Compression.TypesReq[1] wrong: %v", f.Name, f.Compression.TypesReq[1]) + } + } + if len(f.Compression.TypesRes) != 1 { + t.Errorf("%v: len Compression.TypesRes not 1: %v", f.Name, len(f.Compression.TypesRes)) + } else { + if !(f.Compression.TypesReq[0] == "text/plain") { + t.Errorf("%v: Compression.TypesReq[0] wrong: %v", f.Name, f.Compression.TypesReq[0]) + } + } } if f.HTTPIgnoreProbes != "enabled" { diff --git a/go.mod b/go.mod index 8d72d96b..e8d4c653 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,7 @@ require ( github.com/google/go-cmp v0.6.0 github.com/google/renameio v1.0.1 github.com/google/uuid v1.6.0 - github.com/haproxytech/config-parser/v5 v5.1.1-0.20240220100901-1145ec548975 + github.com/haproxytech/config-parser/v5 v5.1.1-0.20240221073837-5b782186def2 github.com/json-iterator/go v1.1.12 github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 github.com/mitchellh/mapstructure v1.5.0 diff --git a/go.sum b/go.sum index 5f9c1257..976f11b1 100644 --- a/go.sum +++ b/go.sum @@ -34,8 +34,8 @@ github.com/google/renameio v1.0.1 h1:Lh/jXZmvZxb0BBeSY5VKEfidcbcbenKjZFzM/q0fSeU github.com/google/renameio v1.0.1/go.mod h1:t/HQoYBZSsWSNK35C6CO/TpPLDVWvxOHboWUAweKUpk= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/haproxytech/config-parser/v5 v5.1.1-0.20240220100901-1145ec548975 h1:CL/3SEvayajAyRHHOmKLsqiwZ8SVwAstCbKEvuxNknI= -github.com/haproxytech/config-parser/v5 v5.1.1-0.20240220100901-1145ec548975/go.mod h1:iy8nBB1eopwYbyeh3FQpjxZUxfcIDyTV9bW0F1t+cVA= +github.com/haproxytech/config-parser/v5 v5.1.1-0.20240221073837-5b782186def2 h1:YXI/15X8xJPrnyO8brmiNaFhOD17Ib9nszHRrlEtuIw= +github.com/haproxytech/config-parser/v5 v5.1.1-0.20240221073837-5b782186def2/go.mod h1:iy8nBB1eopwYbyeh3FQpjxZUxfcIDyTV9bW0F1t+cVA= github.com/haproxytech/go-logger v1.1.0 h1:HgGtYaI1ApkvbQdsm7f9AzQQoxTB7w37criTflh7IQE= github.com/haproxytech/go-logger v1.1.0/go.mod h1:OekUd8HCb7ubxMplzHUPBTHNxZmddOWfOjWclZsqIeM= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= diff --git a/models/compression.go b/models/compression.go index 011fa4be..46e6c7aa 100644 --- a/models/compression.go +++ b/models/compression.go @@ -35,10 +35,17 @@ import ( // // swagger:model compression type Compression struct { + // algo req + // Enum: [identity gzip deflate raw-deflate] + // +kubebuilder:validation:Enum=identity;gzip;deflate;raw-deflate; + AlgoReq string `json:"algo-req,omitempty"` // algorithms Algorithms []string `json:"algorithms,omitempty"` + // algos res + AlgosRes []string `json:"algos-res,omitempty"` + // direction // Enum: [request response both] // +kubebuilder:validation:Enum=request;response;both; @@ -49,16 +56,30 @@ type Compression struct { // types Types []string `json:"types,omitempty"` + + // types req + TypesReq []string `json:"types-req,omitempty"` + + // types res + TypesRes []string `json:"types-res,omitempty"` } // Validate validates this compression func (m *Compression) Validate(formats strfmt.Registry) error { var res []error + if err := m.validateAlgoReq(formats); err != nil { + res = append(res, err) + } + if err := m.validateAlgorithms(formats); err != nil { res = append(res, err) } + if err := m.validateAlgosRes(formats); err != nil { + res = append(res, err) + } + if err := m.validateDirection(formats); err != nil { res = append(res, err) } @@ -69,6 +90,54 @@ func (m *Compression) Validate(formats strfmt.Registry) error { return nil } +var compressionTypeAlgoReqPropEnum []interface{} + +func init() { + var res []string + if err := json.Unmarshal([]byte(`["identity","gzip","deflate","raw-deflate"]`), &res); err != nil { + panic(err) + } + for _, v := range res { + compressionTypeAlgoReqPropEnum = append(compressionTypeAlgoReqPropEnum, v) + } +} + +const ( + + // CompressionAlgoReqIdentity captures enum value "identity" + CompressionAlgoReqIdentity string = "identity" + + // CompressionAlgoReqGzip captures enum value "gzip" + CompressionAlgoReqGzip string = "gzip" + + // CompressionAlgoReqDeflate captures enum value "deflate" + CompressionAlgoReqDeflate string = "deflate" + + // CompressionAlgoReqRawDashDeflate captures enum value "raw-deflate" + CompressionAlgoReqRawDashDeflate string = "raw-deflate" +) + +// prop value enum +func (m *Compression) validateAlgoReqEnum(path, location string, value string) error { + if err := validate.EnumCase(path, location, value, compressionTypeAlgoReqPropEnum, true); err != nil { + return err + } + return nil +} + +func (m *Compression) validateAlgoReq(formats strfmt.Registry) error { + if swag.IsZero(m.AlgoReq) { // not required + return nil + } + + // value enum + if err := m.validateAlgoReqEnum("algo-req", "body", m.AlgoReq); err != nil { + return err + } + + return nil +} + var compressionAlgorithmsItemsEnum []interface{} func init() { @@ -105,6 +174,42 @@ func (m *Compression) validateAlgorithms(formats strfmt.Registry) error { return nil } +var compressionAlgosResItemsEnum []interface{} + +func init() { + var res []string + if err := json.Unmarshal([]byte(`["identity","gzip","deflate","raw-deflate"]`), &res); err != nil { + panic(err) + } + for _, v := range res { + compressionAlgosResItemsEnum = append(compressionAlgosResItemsEnum, v) + } +} + +func (m *Compression) validateAlgosResItemsEnum(path, location string, value string) error { + if err := validate.EnumCase(path, location, value, compressionAlgosResItemsEnum, true); err != nil { + return err + } + return nil +} + +func (m *Compression) validateAlgosRes(formats strfmt.Registry) error { + if swag.IsZero(m.AlgosRes) { // not required + return nil + } + + for i := 0; i < len(m.AlgosRes); i++ { + + // value enum + if err := m.validateAlgosResItemsEnum("algos-res"+"."+strconv.Itoa(i), "body", m.AlgosRes[i]); err != nil { + return err + } + + } + + return nil +} + var compressionTypeDirectionPropEnum []interface{} func init() { diff --git a/models/compression_compare.go b/models/compression_compare.go index a89ce5b8..1b2a45c5 100644 --- a/models/compression_compare.go +++ b/models/compression_compare.go @@ -33,10 +33,18 @@ package models func (s Compression) Equal(t Compression, opts ...Options) bool { opt := getOptions(opts...) + if s.AlgoReq != t.AlgoReq { + return false + } + if !equalComparableSlice(s.Algorithms, t.Algorithms, opt) { return false } + if !equalComparableSlice(s.AlgosRes, t.AlgosRes, opt) { + return false + } + if s.Direction != t.Direction { return false } @@ -49,6 +57,14 @@ func (s Compression) Equal(t Compression, opts ...Options) bool { return false } + if !equalComparableSlice(s.TypesReq, t.TypesReq, opt) { + return false + } + + if !equalComparableSlice(s.TypesRes, t.TypesRes, opt) { + return false + } + return true } @@ -69,10 +85,18 @@ func (s Compression) Diff(t Compression, opts ...Options) map[string][]interface opt := getOptions(opts...) diff := make(map[string][]interface{}) + if s.AlgoReq != t.AlgoReq { + diff["AlgoReq"] = []interface{}{s.AlgoReq, t.AlgoReq} + } + if !equalComparableSlice(s.Algorithms, t.Algorithms, opt) { diff["Algorithms"] = []interface{}{s.Algorithms, t.Algorithms} } + if !equalComparableSlice(s.AlgosRes, t.AlgosRes, opt) { + diff["AlgosRes"] = []interface{}{s.AlgosRes, t.AlgosRes} + } + if s.Direction != t.Direction { diff["Direction"] = []interface{}{s.Direction, t.Direction} } @@ -85,5 +109,13 @@ func (s Compression) Diff(t Compression, opts ...Options) map[string][]interface diff["Types"] = []interface{}{s.Types, t.Types} } + if !equalComparableSlice(s.TypesReq, t.TypesReq, opt) { + diff["TypesReq"] = []interface{}{s.TypesReq, t.TypesReq} + } + + if !equalComparableSlice(s.TypesRes, t.TypesRes, opt) { + diff["TypesRes"] = []interface{}{s.TypesRes, t.TypesRes} + } + return diff } diff --git a/models/compression_compare_test.go b/models/compression_compare_test.go index 7f2258d5..d80f5711 100644 --- a/models/compression_compare_test.go +++ b/models/compression_compare_test.go @@ -171,7 +171,7 @@ func TestCompressionDiffFalse(t *testing.T) { for _, sample := range samples { result := sample.a.Diff(sample.b) - if len(result) != 4 { + if len(result) != 8 { json := jsoniter.ConfigCompatibleWithStandardLibrary a, err := json.Marshal(&sample.a) if err != nil { @@ -181,7 +181,7 @@ func TestCompressionDiffFalse(t *testing.T) { if err != nil { t.Errorf(err.Error()) } - t.Errorf("Expected Compression to be different in 4 cases, but it is not (%d) %s %s", len(result), a, b) + t.Errorf("Expected Compression to be different in 8 cases, but it is not (%d) %s %s", len(result), a, b) } } } diff --git a/specification/build/haproxy_spec.yaml b/specification/build/haproxy_spec.yaml index 06ac2b47..69551fe4 100644 --- a/specification/build/haproxy_spec.yaml +++ b/specification/build/haproxy_spec.yaml @@ -9842,6 +9842,14 @@ definitions: x-go-name: ReturnHeader compression: properties: + algo-req: + enum: + - identity + - gzip + - deflate + - raw-deflate + type: string + x-omitempty: true algorithms: items: enum: @@ -9852,6 +9860,16 @@ definitions: type: string type: array x-omitempty: true + algos-res: + items: + enum: + - identity + - gzip + - deflate + - raw-deflate + type: string + type: array + x-omitempty: true direction: enum: - request @@ -9866,6 +9884,16 @@ definitions: type: string type: array x-omitempty: true + types-req: + items: + type: string + type: array + x-omitempty: true + types-res: + items: + type: string + type: array + x-omitempty: true type: object source: properties: diff --git a/specification/models/configuration/misc.yaml b/specification/models/configuration/misc.yaml index b2144f33..ddd0374b 100644 --- a/specification/models/configuration/misc.yaml +++ b/specification/models/configuration/misc.yaml @@ -314,6 +314,26 @@ compression: type: string enum: [request, response, both] x-omitempty: true + types-req: + type: array + x-omitempty: true + items: + type: string + types-res: + type: array + x-omitempty: true + items: + type: string + algo-req: + type: string + x-omitempty: true + enum: [identity, gzip, deflate, raw-deflate] + algos-res: + type: array + x-omitempty: true + items: + type: string + enum: [identity, gzip, deflate, raw-deflate] stats_http_request: type: object required: