diff --git a/.golangci.yml b/.golangci.yml index 7ff8186f..91c1fcc3 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -67,7 +67,10 @@ issues: # bugs of typecheck linter - "undeclared name: `shellquote`" - "github.com/kballard/go-shellquote\" imported but not used" - - "github.com/haproxytech/config-parser/v5/types\" imported but not used" + - "github.com/haproxytech/client-native/v5/config-parser/types\" imported but not used" + - "unused-parameter: parameter 'comment' seems to be unused" + - "unused-parameter: parameter 'parts' seems to be unused" + - "unused-parameter: parameter 'parserType' seems to be unused" run: skip-dirs: diff --git a/Makefile b/Makefile index 8cba3d91..07b5d114 100644 --- a/Makefile +++ b/Makefile @@ -18,12 +18,16 @@ e2e-docker: docker build -f e2e/Dockerfile --build-arg GO_VERSION=${GO_VERSION} --build-arg HAPROXY_VERSION=${DOCKER_HAPROXY_VERSION} -t client-native-test:${DOCKER_HAPROXY_VERSION} . docker run --rm -t client-native-test:${DOCKER_HAPROXY_VERSION} +.PHONY: gentypes +gentypes: + cd config-parser && go run generate/*.go ${PROJECT_PATH}/config-parser + .PHONY: spec spec: go run specification/build/build.go -file specification/haproxy-spec.yaml > specification/build/haproxy_spec.yaml .PHONY: models -models: spec swagger-check +models: gentypes spec swagger-check ./bin/swagger generate model --additional-initialism=FCGI -f ${PROJECT_PATH}/specification/build/haproxy_spec.yaml -r ${PROJECT_PATH}/specification/copyright.txt -m models -t ${PROJECT_PATH} .PHONY: swagger-check diff --git a/config-parser/README.md b/config-parser/README.md new file mode 100644 index 00000000..6fc85209 --- /dev/null +++ b/config-parser/README.md @@ -0,0 +1,113 @@ +## HAProxy configuration parser + +### autogenerated code +if you change types/types.go you need to run +```bash +make gentypes +``` + +### Example + +```go +package main + +import ( + "github.com/haproxytech/client-native/v5/config-parser" + "github.com/haproxytech/client-native/v5/config-parser/options" + "github.com/haproxytech/client-native/v5/config-parser/parsers/http/actions" + // ... +) +// ... + +func main() { + p, err := parser.New(options.Path("config.cfg")) + /* p, err := parser.New( + options.UseMd5Hash, + options.Path("config.cfg") + )*/ + if err != nil { + log.Panic(err) + } + + { + data, _ := p.Get(parser.Comments, parser.CommentsSectionName, "# _version", true) + if err == errors.ErrFetch { + log.Panicln("we have an fetch error !!") + } + ver, _ := data.(*types.Int64C) + ver.Value = ver.Value + 1 + } + + { + p.Set(parser.Frontends, "http", "option forwardfor", types.OptionForwardFor{}) + } + + { + // for options that can exists multiple times in config Insert is preffered + // + // setting http-request & http-response is a bit different + // since they accept multiple structs + httpRequestActionDeny := &actions.Deny{ + DenyStatus: "0", + Cond: "unless", + CondTest: "{ src 127.0.0.1 }", + } + err = p.Insert(parser.Backends, "web_servers", "http-request", httpRequestActionDeny) + // you can also choose index where action should be inserted + err = p.Insert(parser.Backends, "web_servers", "http-request", httpRequestActionDeny, 2) + } + + { + data, err := p.Get(parser.Global, parser.GlobalSectionName, "stats socket") + if err != nil { + log.Panicln(err) + } + val, _ := data.([]types.Socket) + log.Println(val[0]) + val[0].Path = "$PWD/haproxy-runtime-api.1.sock" + log.Println(val[0]) + } + + { + data, err := p.Get(parser.Global, parser.GlobalSectionName, "daemon") + log.Println(data, err) + if err == errors.ErrFetch { + log.Panicln("we have an fetch error !!") + } + //remove it + p.Set(parser.Global, parser.GlobalSectionName, "daemon", nil) + } + + { + datar, err := p.Get(parser.Resolvers, "ns1", "nameserver") + if err == nil { + ns := datar.([]types.Nameserver) + log.Println(ns[0].Name, ns[0].Address) + log.Println(ns[1].Name, ns[1].Address) + ns[1].Name = "hahaha" + ns[0].Address = "0.0.0.0:8080" + } + datar, err = p.Get(parser.Resolvers, "ns1", "nameserver") + if err == nil { + ns := datar.([]types.Nameserver) + log.Println(ns[0].Name, ns[0].Address) + log.Println(ns[1].Name, ns[1].Address) + } + } + + { + log.Println("nbproc ==================================================") + data, err := p.Get(parser.Global, parser.GlobalSectionName, "nbproc") + if err != nil { + log.Println(err) + } else { + d := data.(*types.Int64C) + log.Println(d.Value) + d.Value = 5 + } + } + + p.Save(configFilename) +} + +``` diff --git a/config-parser/assets/images/haproxy-weblogo-210x49.png b/config-parser/assets/images/haproxy-weblogo-210x49.png new file mode 100644 index 00000000..9fb51af0 Binary files /dev/null and b/config-parser/assets/images/haproxy-weblogo-210x49.png differ diff --git a/config-parser/bin/lint-check.sh b/config-parser/bin/lint-check.sh new file mode 100644 index 00000000..0383b626 --- /dev/null +++ b/config-parser/bin/lint-check.sh @@ -0,0 +1,7 @@ +#!/bin/sh +V=$(./golangci-lint --version) + +case "$V" in + *$GOLANGCI_LINT_VERSION*) echo "$V" ;; + *) curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(pwd) "v$GOLANGCI_LINT_VERSION" ;; +esac diff --git a/config-parser/common/common.go b/config-parser/common/common.go new file mode 100644 index 00000000..2650b840 --- /dev/null +++ b/config-parser/common/common.go @@ -0,0 +1,142 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package common + +import ( + "strings" +) + +// StringSplitIgnoreEmpty while spliting, removes empty items +func StringSplitIgnoreEmpty(s string, separators ...rune) []string { + f := func(c rune) bool { + willSplit := false + for _, sep := range separators { + if c == sep { + willSplit = true + break + } + } + return willSplit + } + return strings.FieldsFunc(s, f) +} + +// StringSplitWithCommentIgnoreEmpty while splitting, removes empty items, if we have comment, separate it +func StringSplitWithCommentIgnoreEmpty(s string) (data []string, comment string) { //nolint:gocognit,nonamedreturns + data = []string{} + + singleQuoteActive := false + doubleQuoteActive := false + var buff strings.Builder + for index, c := range s { + if !singleQuoteActive && !doubleQuoteActive { + if (c == '#' && index == 0) || (c == '#' && s[index-1] != '\\') { + if buff.Len() > 0 { + data = append(data, buff.String()) + buff.Reset() + } + index++ + for ; index < len(s); index++ { + if s[index] != ' ' { + break + } + } + comment = s[index:] + return data, comment + } + if (c == ' ' && index == 0) || (c == ' ' && s[index-1] != '\\') || c == '\t' { + if buff.Len() > 0 { + data = append(data, buff.String()) + buff.Reset() + } + continue + } + } + buff.WriteRune(c) + if c == '"' { + if doubleQuoteActive { + if index == 0 || s[index-1] != '\\' { + doubleQuoteActive = false + } + } else if !singleQuoteActive { + if index == 0 || s[index-1] != '\\' { + doubleQuoteActive = true + } + } + } + if c == '\'' { + if singleQuoteActive { + singleQuoteActive = false + } else if !doubleQuoteActive { + if index == 0 || s[index-1] != '\\' { + singleQuoteActive = true + } + } + } + } + if buff.Len() > 0 { + data = append(data, buff.String()) + } + return data, comment +} + +// StringExtractComment checks if comment is added +func StringExtractComment(s string) string { + p := StringSplitIgnoreEmpty(s, '#') + if len(p) > 1 { + return p[len(p)-1] + } + return "" +} + +// SplitRequest searches for "if" or "unless" and returns result +func SplitRequest(parts []string) (command, condition []string) { //nolint:nonamedreturns + if len(parts) == 0 { + return []string{}, []string{} + } + index := 0 + found := false + for index < len(parts) { + switch parts[index] { + case "if", "unless": + found = true + } + if found { + break + } + index++ + } + command = parts[:index] + condition = parts[index:] + return command, condition +} + +// CutRight slices string around the last occurrence of sep returning the text +// before and after sep. The found result reports whether sep appears in s. If +// sep does not appear in s, cut returns s, "", false. +func CutRight(s, sep string) (before, after string, found bool) { //nolint:nonamedreturns + pos := strings.LastIndex(s, sep) + if pos < 0 { + before = s + found = false + } else { + before = s[:pos] + after = s[pos+len(sep):] + found = true + } + return before, after, found +} diff --git a/config-parser/common/common_test.go b/config-parser/common/common_test.go new file mode 100644 index 00000000..5ee2b354 --- /dev/null +++ b/config-parser/common/common_test.go @@ -0,0 +1,124 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package common //nolint:testpackage + +import ( + "reflect" + "testing" +) + +func TestStringSplitWithCommentIgnoreEmpty(t *testing.T) { + tests := []struct { + name string + s string + wantData []string + wantComment string + }{ + {"simple", " http-request deny deny_status 400 # deny", []string{"http-request", "deny", "deny_status", "400"}, "deny"}, + {"empty comment", " http-request deny deny_status 400 # ", []string{"http-request", "deny", "deny_status", "400"}, ""}, + {"no comment", " http-request deny deny_status 400 ", []string{"http-request", "deny", "deny_status", "400"}, ""}, + {"single quote", " acl 'fdsfsdfsd sdf s f' abc\\ def ", []string{"acl", "'fdsfsdfsd sdf s f'", "abc\\ def"}, ""}, + {"escaped space", ` acl abc\ def `, []string{"acl", `abc\ def`}, ""}, + {"escaped space with #", ` acl abc\ def #comment`, []string{"acl", `abc\ def`}, "comment"}, + {"escaped space with # formated", ` acl abc\ def # comment`, []string{"acl", `abc\ def`}, "comment"}, + {"single quote escaped double", ` acl 'fdsfsdfsd "sdf" s f' abc\ def `, []string{"acl", `'fdsfsdfsd "sdf" s f'`, `abc\ def`}, ""}, + {"double quote escaped single", ` acl "fdsfsdfsd 'sdf' s f" abc\ def `, []string{"acl", `"fdsfsdfsd 'sdf' s f"`, `abc\ def`}, ""}, + {"escaped single", ` abc \'def ghi\' jkl`, []string{"abc", `\'def`, `ghi\'`, `jkl`}, ""}, + {"escaped double", ` abc \"def ghi\" jkl`, []string{"abc", `\"def`, `ghi\"`, `jkl`}, ""}, + {"escaped double", ` abc "defghi\"" jkl`, []string{"abc", `"defghi\""`, `jkl`}, ""}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + gotData, gotComment := StringSplitWithCommentIgnoreEmpty(tt.s) + if !reflect.DeepEqual(gotData, tt.wantData) { + t.Errorf("StringSplitWithCommentIgnoreEmpty() gotData = %v, want %v", gotData, tt.wantData) + } + if gotComment != tt.wantComment { + t.Errorf("StringSplitWithCommentIgnoreEmpty() gotComment = %v, want %v", gotComment, tt.wantComment) + } + }) + } +} + +func TestCutRight(t *testing.T) { + tests := []struct { + name string + s string + sep string + before string + after string + found bool + }{ + { + name: "simple", + s: "ab:cd:ef", + sep: ":", + before: "ab:cd", + after: "ef", + found: true, + }, + { + name: "multi-characters-sep", + s: "ab:-:cd:-:ef", + sep: ":-:", + before: "ab:-:cd", + after: "ef", + found: true, + }, + { + name: "sep-at-start", + s: ":abcd", + sep: ":", + before: "", + after: "abcd", + found: true, + }, + { + name: "sep-at-end", + s: "abcd:", + sep: ":", + before: "abcd", + after: "", + found: true, + }, + { + name: "no-sep", + s: "abcd", + sep: ":", + before: "abcd", + after: "", + found: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + before, after, found := CutRight(tt.s, tt.sep) + if before != tt.before { + t.Errorf("Part before separator doesn't match expected: %q != %q", before, tt.before) + return + } + if after != tt.after { + t.Errorf("Part after separator doesn't match expected: %q != %q", after, tt.after) + return + } + if found != tt.found { + t.Errorf("Found result doesn't match expected: %v != %v", found, tt.found) + return + } + }) + } +} diff --git a/config-parser/common/expression.go b/config-parser/common/expression.go new file mode 100644 index 00000000..ace92118 --- /dev/null +++ b/config-parser/common/expression.go @@ -0,0 +1,33 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package common + +import "strings" + +// Expression is standard HAProxy expression formed by a sample-fetch followed by some converters. +type Expression struct { + Expr []string +} + +func (e *Expression) Parse(expression []string) error { + e.Expr = expression + return nil +} + +func (e *Expression) String() string { + return strings.Join(e.Expr, " ") +} diff --git a/config-parser/common/parser-data.go b/config-parser/common/parser-data.go new file mode 100644 index 00000000..98cd797b --- /dev/null +++ b/config-parser/common/parser-data.go @@ -0,0 +1,19 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package common + +type ParserData interface{} diff --git a/config-parser/common/return-result-line.go b/config-parser/common/return-result-line.go new file mode 100644 index 00000000..5e450319 --- /dev/null +++ b/config-parser/common/return-result-line.go @@ -0,0 +1,22 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package common + +type ReturnResultLine struct { + Data string + Comment string +} diff --git a/config-parser/errors/parse.go b/config-parser/errors/parse.go new file mode 100644 index 00000000..aa77bf03 --- /dev/null +++ b/config-parser/errors/parse.go @@ -0,0 +1,59 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package errors + +import ( + "errors" + "fmt" +) + +// ParseError struct for creating parse errors +type ParseError struct { + Parser string + Line string + Message string +} + +func (e *ParseError) Error() string { + return fmt.Sprintf("%s:%s: Parse error on %s", e.Parser, e.Message, e.Line) +} + +var ErrAttributeNotFound = errors.New("attribute not found") + +var ErrFetch = errors.New("no data") + +var ErrIndexOutOfRange = errors.New("index out of range") + +var ErrInvalidData = errors.New("invalid data") + +var ErrParserMissing = errors.New("parser missing") + +var ErrSectionAlreadyExists = errors.New("section already exists") + +var ErrSectionMissing = errors.New("section missing") + +var ErrSectionTypeMissing = errors.New("section type missing") + +var ErrSectionTypeNotAllowed = errors.New("section type not allowed") + +var ErrScopeMissing = errors.New("scope missing") + +var ErrScopeAlreadyExists = errors.New("scope already exists") + +var ErrFromDefaultsSectionMissing = errors.New("defaults section specified in from does not exist") + +var ErrCircularDependency = errors.New("circular dependency detected") diff --git a/config-parser/fetch.go b/config-parser/fetch.go new file mode 100644 index 00000000..f2ca30ed --- /dev/null +++ b/config-parser/fetch.go @@ -0,0 +1,358 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package parser + +import ( + "fmt" + "sort" + + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/sorter" +) + +func (p *configParser) lock() { + p.mutex.Lock() +} + +func (p *configParser) unLock() { + p.mutex.Unlock() +} + +// Get get attribute from defaults section +func (p *configParser) Get(sectionType Section, sectionName string, attribute string, createIfNotExist ...bool) (common.ParserData, error) { + p.lock() + defer p.unLock() + st, ok := p.Parsers[sectionType] + if !ok { + return nil, errors.ErrSectionMissing + } + section, ok := st[sectionName] + if !ok { + return nil, errors.ErrSectionMissing + } + createNew := false + if len(createIfNotExist) > 0 && createIfNotExist[0] { + createNew = true + } + return section.Get(attribute, createNew) +} + +// GetPreComments get attribute from section +func (p *configParser) GetPreComments(sectionType Section, sectionName string, attribute string) ([]string, error) { + p.lock() + defer p.unLock() + st, ok := p.Parsers[sectionType] + if !ok { + return nil, errors.ErrSectionMissing + } + section, ok := st[sectionName] + if !ok { + return nil, errors.ErrSectionMissing + } + return section.GetPreComments(attribute) +} + +// GetOne get attribute from section +func (p *configParser) GetOne(sectionType Section, sectionName string, attribute string, index ...int) (common.ParserData, error) { + p.lock() + defer p.unLock() + setIndex := -1 + if len(index) > 0 && index[0] > -1 { + setIndex = index[0] + } + st, ok := p.Parsers[sectionType] + if !ok { + return nil, errors.ErrSectionMissing + } + section, ok := st[sectionName] + if !ok { + return nil, errors.ErrSectionMissing + } + return section.GetOne(attribute, setIndex) +} + +// SectionsGet lists all sections of certain type +func (p *configParser) SectionsGet(sectionType Section) ([]string, error) { + p.lock() + defer p.unLock() + st, ok := p.Parsers[sectionType] + if !ok { + return nil, errors.ErrSectionMissing + } + result := make([]string, len(st)) + index := 0 + for sectionName := range st { + result[index] = sectionName + index++ + } + return result, nil +} + +// SectionsDelete deletes one section of sectionType +func (p *configParser) SectionsDelete(sectionType Section, sectionName string) error { + p.lock() + defer p.unLock() + if _, ok := p.Parsers[sectionType]; !ok { + return errors.ErrSectionMissing + } + delete(p.Parsers[sectionType], sectionName) + return nil +} + +// SectionsCreate creates one section of sectionType +func (p *configParser) SectionsCreate(sectionType Section, sectionName string) error { + p.lock() + defer p.unLock() + st, ok := p.Parsers[sectionType] + if !ok { + return errors.ErrSectionMissing + } + _, ok = st[sectionName] + if ok { + return errors.ErrSectionAlreadyExists + } + + parsers := ConfiguredParsers{ + State: "", + Active: p.Parsers[Comments][CommentsSectionName], + Comments: p.Parsers[Comments][CommentsSectionName], + Global: p.Parsers[Global][GlobalSectionName], + } + + parts := []string{string(sectionType), sectionName} + comment := "" + p.ProcessLine(fmt.Sprintf("%s %s", sectionType, sectionName), parts, comment, parsers) + return nil +} + +// SectionsDefaultsFromGet returns dedicated defaults section for particular section. +// in configuration: +// +// defaults DefaultsName +// mode tcp +// +// frontend FrontendName from DefaultsName +// ... +// +// SectionsDefaultsFromGet(Frontends,"FrontendName") => "DefaultsName",nil +func (p *configParser) SectionsDefaultsFromGet(sectionType Section, sectionName string) (string, error) { + p.lock() + defer p.unLock() + st, ok := p.Parsers[sectionType] + if !ok { + return "", errors.ErrSectionTypeMissing + } + section, ok := st[sectionName] + if !ok { + return "", errors.ErrSectionMissing + } + + return section.DefaultSectionName, nil +} + +// SectionsDefaultsFromSet set default section for section. +// in configuration: +// +// defaults DefaultsName1 +// mode tcp +// +// defaults DefaultsName2 +// mode tcp +// +// frontend FrontendName from DefaultsName1 +// ... +// +// SectionsDefaultsFromSet(Frontends,"FrontendName", "DefaultsName2") => nil +// +// ONLY defaults, frontend, backend and listen sections can be used here +func (p *configParser) SectionsDefaultsFromSet(sectionType Section, sectionName, defaultsSection string) error { + p.lock() + defer p.unLock() + switch sectionType { //nolint:exhaustive + case Defaults: + // for defaults we need to check for circular dependencies + // and whether that section exists or not due to sorting method + sections := p.Parsers[Defaults] + listDefaults := []sorter.Section{} + for k, v := range sections { + s := sorter.Section{ + Name: k, + From: v.DefaultSectionName, + } + if s.Name == sectionName { + s.From = defaultsSection + } + listDefaults = append(listDefaults, s) + } + err := sorter.Sort(listDefaults) + if err != nil { + return err + } + case Frontends, Backends, Listen: + default: + // catch all other sections + return errors.ErrSectionTypeNotAllowed + } + + st, ok := p.Parsers[sectionType] + if !ok { + return errors.ErrSectionTypeMissing + } + section, ok := st[sectionName] + if !ok { + return errors.ErrSectionMissing + } + // if not set to empty, do extra validation + if defaultsSection != "" { + stDef, ok := p.Parsers[Defaults] + if !ok { + return errors.ErrSectionTypeMissing + } + _, ok = stDef[defaultsSection] + if !ok { + return errors.ErrFromDefaultsSectionMissing + } + } + section.DefaultSectionName = defaultsSection + return nil +} + +// Set sets attribute from section, can be nil to disable/remove +func (p *configParser) Set(sectionType Section, sectionName string, attribute string, data common.ParserData, index ...int) error { + p.lock() + defer p.unLock() + setIndex := -1 + if len(index) > 0 && index[0] > -1 { + setIndex = index[0] + } + st, ok := p.Parsers[sectionType] + if !ok { + return errors.ErrSectionMissing + } + section, ok := st[sectionName] + if !ok { + return errors.ErrSectionMissing + } + return section.Set(attribute, data, setIndex) +} + +// Set sets line comment before attribute from section, can be nil to disable/remove +func (p *configParser) SetPreComments(sectionType Section, sectionName string, attribute string, preComment []string) error { + p.lock() + defer p.unLock() + st, ok := p.Parsers[sectionType] + if !ok { + return errors.ErrSectionMissing + } + section, ok := st[sectionName] + if !ok { + return errors.ErrSectionMissing + } + return section.SetPreComments(attribute, preComment) +} + +// Delete remove attribute on defined index, in case of single attributes, index is ignored +func (p *configParser) Delete(sectionType Section, sectionName string, attribute string, index ...int) error { + p.lock() + defer p.unLock() + setIndex := -1 + if len(index) > 0 && index[0] > -1 { + setIndex = index[0] + } + st, ok := p.Parsers[sectionType] + if !ok { + return errors.ErrSectionMissing + } + section, ok := st[sectionName] + if !ok { + return errors.ErrSectionMissing + } + return section.Delete(attribute, setIndex) +} + +// Insert put attribute on defined index, in case of single attributes, index is ignored +func (p *configParser) Insert(sectionType Section, sectionName string, attribute string, data common.ParserData, index ...int) error { + p.lock() + defer p.unLock() + setIndex := -1 + if len(index) > 0 && index[0] > -1 { + setIndex = index[0] + } + st, ok := p.Parsers[sectionType] + if !ok { + return errors.ErrSectionMissing + } + section, ok := st[sectionName] + if !ok { + return errors.ErrSectionMissing + } + return section.Insert(attribute, data, setIndex) +} + +// HasParser checks if we have a parser for attribute +func (p *configParser) HasParser(sectionType Section, attribute string) bool { + p.lock() + defer p.unLock() + st, ok := p.Parsers[sectionType] + if !ok { + return false + } + sectionName := "" + for name := range st { + sectionName = name + + break + } + section, ok := st[sectionName] + if !ok { + return false + } + return section.HasParser(attribute) +} + +func (p *configParser) getSortedList(data map[string]*Parsers) []string { + result := make([]string, len(data)) + index := 0 + for parserSectionName := range data { + result[index] = parserSectionName + index++ + } + sort.Strings(result) + return result +} + +// getSortedListWithFrom returns list of parses sorted, +// since every section can have a from that might depend on, +// we take that into account +func getSortedListWithFrom(data map[string]*Parsers) ([]string, error) { + sortedSections := make([]sorter.Section, len(data)) + index := 0 + for parserSectionName := range data { + sortedSections[index] = sorter.Section{ + Name: parserSectionName, + From: data[parserSectionName].DefaultSectionName, + } + index++ + } + err := sorter.Sort(sortedSections) + result := make([]string, len(data)) + for index, value := range sortedSections { + result[index] = value.Name + } + return result, err +} diff --git a/config-parser/generate/config-file.go b/config-parser/generate/config-file.go new file mode 100644 index 00000000..f0118af4 --- /dev/null +++ b/config-parser/generate/config-file.go @@ -0,0 +1,373 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +import ( + "fmt" + "log" + "path" + "sort" + "strings" + + "github.com/google/renameio/maybe" + "golang.org/x/text/cases" + "golang.org/x/text/language" +) + +type AliasTestData struct { + Alias string + Test string +} + +type DefaultTestData struct { + Test string + Default string +} + +type TableTestData struct { + Test string + Table string +} + +type Data struct { //nolint:maligned + ParserMultiple bool + ParserSections []string + ParserName string + ParserSecondName string + StructName string + ParserType string + ParserTypeOverride string + NoInit bool + NoName bool + NoParse bool + NoGet bool + NoSections bool + IsInterface bool + Dir string + ModeOther bool + TestOK []string + TestOKDefaults []string + TestOKFrontend []string + TestOKBackend []string + TestOKEscaped []string + TestFail []string + TestFailEscaped []string + TestAliasOK []AliasTestData + TestAliasFail []AliasTestData + TestDefault []DefaultTestData + TestTableOK []TableTestData + TestSkip bool + DataDir string + Deprecated bool + HasAlias bool + HasDefault bool + HasTable bool +} + +type ConfigFile struct { + Section map[string][]string + SectionAll map[string][]string + Tests strings.Builder +} + +func (c *ConfigFile) AddParserData(parser Data) { //nolint:gocognit + sections := parser.ParserSections + testOK := parser.TestOK + testOKDefaults := parser.TestOKDefaults + testOKFrontend := parser.TestOKFrontend + testOKBackend := parser.TestOKBackend + TestOKEscaped := parser.TestOKEscaped + if len(sections) == 0 && !parser.NoSections { + log.Fatalf("parser %s does not have any section defined", parser.ParserName) + } + var lines []string + var linesDefaults []string + var linesFrontend []string + var linesBackend []string + var lines2 []string + for _, section := range sections { + _, ok := c.Section[section] + if !ok { + c.Section[section] = []string{} + if c.SectionAll == nil { + c.SectionAll = make(map[string][]string) + } + c.SectionAll[section] = []string{} + } + // line = testOK[0] + if parser.ParserMultiple { + lines = testOK + //nolint:gosimple + for _, line := range testOK { + c.Section[section] = append(c.Section[section], line) + } + // c.Section[s] = append(c.Section[s], testOK...) + } else { + lines = []string{testOK[0]} + c.Section[section] = append(c.Section[section], testOK[0]) + } + if len(parser.TestTableOK) > 0 { + for _, line := range parser.TestTableOK { + lines = append(lines, line.Table) + c.Section[section] = append(c.Section[section], line.Table) + } + } + c.SectionAll[section] = append(c.SectionAll[section], testOK...) + if section == "defaults" { + if parser.ParserMultiple { + linesDefaults = testOKDefaults + //nolint:gosimple + for _, line := range testOKDefaults { + c.Section[section] = append(c.Section[section], line) + } + } else if len(testOKDefaults) > 0 { + linesDefaults = []string{testOKDefaults[0]} + c.Section[section] = append(c.Section[section], testOKDefaults[0]) + } + c.SectionAll[section] = append(c.SectionAll[section], testOKDefaults...) + } + if section == "frontend" { + if parser.ParserMultiple { + linesFrontend = testOKFrontend + //nolint:gosimple + for _, line := range testOKFrontend { + c.Section[section] = append(c.Section[section], line) + } + } else if len(testOKFrontend) > 0 { + linesFrontend = []string{testOKFrontend[0]} + c.Section[section] = append(c.Section[section], testOKFrontend[0]) + } + c.SectionAll[section] = append(c.SectionAll[section], testOKFrontend...) + } + if section == "backend" { + if parser.ParserMultiple { + linesBackend = testOKBackend + //nolint:gosimple + for _, line := range testOKBackend { + c.Section[section] = append(c.Section[section], line) + } + } else if len(testOKBackend) > 0 { + linesBackend = []string{testOKBackend[0]} + c.Section[section] = append(c.Section[section], testOKBackend[0]) + } + c.SectionAll[section] = append(c.SectionAll[section], testOKBackend...) + } + if parser.ParserMultiple { + lines2 = TestOKEscaped + //nolint:gosimple + for _, line := range TestOKEscaped { + c.Section[section] = append(c.Section[section], line) + } + // c.Section[s] = append(c.Section[s], TestOKEscaped...) + } else if len(TestOKEscaped) > 0 { + lines2 = []string{TestOKEscaped[0]} + c.Section[section] = append(c.Section[section], TestOKEscaped[0]) + } + c.SectionAll[section] = append(c.SectionAll[section], TestOKEscaped...) + } + if len(lines) == 0 && len(lines2) == 0 { + if parser.NoSections { + return + } else if !parser.Deprecated { + log.Fatalf("parser %s does not have any tests defined", parser.ParserName) + } + } + if !parser.NoSections { + for _, line := range lines { + c.Tests.WriteString(fmt.Sprintf(" {` %s\n`, %d},\n", line, len(sections))) + } + for _, line := range linesDefaults { + c.Tests.WriteString(fmt.Sprintf(" {` %s\n`, 1},\n", line)) + } + for _, line := range linesFrontend { + c.Tests.WriteString(fmt.Sprintf(" {` %s\n`, 1},\n", line)) + } + for _, line := range linesBackend { + c.Tests.WriteString(fmt.Sprintf(" {` %s\n`, 1},\n", line)) + } + } +} + +func (c *ConfigFile) String() string { + var result strings.Builder + + result.WriteString(license) + result.WriteString("package configs\n\n") + result.WriteString("const generatedConfig = `# _version=1\n# HAProxy Technologies\n# https://www.haproxy.com/\n# sections are in alphabetical order (except global & default) for code generation\n\n") + + first := true + sectionNames := make([]string, len(c.Section)-1) + index := 0 + for sectionName := range c.Section { + if sectionName == "global" { + continue + } + sectionNames[index] = sectionName + index++ + } + sort.Strings(sectionNames) + + writeSection := func(sectionName string) { + if !first { + result.WriteString("\n") + } else { + first = false + } + result.WriteString(sectionName) + result.WriteString(" test\n") + lines := c.Section[sectionName] + for _, line := range lines { + result.WriteString(" ") + result.WriteString(line) + result.WriteString("\n") + } + } + + writeSection("global") + for _, sectionName := range sectionNames { + writeSection(sectionName) + } + result.WriteString("`\n\n") + + result.WriteString("var configTests = []configTest{") + result.WriteString(c.Tests.String()) + result.WriteString("}") + + result.WriteString("\n") + return result.String() +} + +func (c *ConfigFile) StringFiles(baseFolder string) { + files := map[string][]byte{} + + header := license + "\npackage integration_test\n\n" + + sectionTypes := make([]string, len(c.SectionAll)-1) + index := 0 + for sectionName := range c.SectionAll { + if sectionName == "global" { + continue + } + sectionTypes[index] = sectionName + index++ + } + sort.Strings(sectionTypes) + usedNiceNames := map[string]struct{}{} + + writeSection := func(sectionType string) { + lines := c.SectionAll[sectionType] + file := files[sectionType] + if len(file) < 1 { + file = append(file, []byte(header)...) + } + for _, line := range lines { + niceName := getNiceName(sectionType) + "_" + getNiceName(line) + exists := true + for exists { + _, exists = usedNiceNames[niceName] + if exists { + niceName += "_" + } + } + usedNiceNames[niceName] = struct{}{} + sectionName := " test" + if sectionType == "global" { + sectionName = "" + } + oneTest := "const " + niceName + " = `\n" + sectionType + sectionName + "\n" + " " + line + "\n`" + "\n" + file = append(file, []byte(oneTest)...) + files[sectionType] = file + } + } + + sectionTypes = append(sectionTypes, "global") //nolint:makezero + for _, sectionName := range sectionTypes { + writeSection(sectionName) + for name, data := range files { + filePath := path.Join(baseFolder, name+"_data_test.go") + log.Println(filePath) + saveFile(filePath, string(data)) + } + files = map[string][]byte{} + + var testFile strings.Builder + testName := cases.Title(language.Und, cases.NoLower).String(getNiceName(sectionName)) + testFile.WriteString(strings.Replace(testHeader, "TestWholeConfigsSections", "TestWholeConfigsSections"+testName, 1)) + sortedNames := []string{} + for name := range usedNiceNames { + if strings.HasPrefix(name, sectionName) { + sortedNames = append(sortedNames, name) + } + } + sort.Strings(sortedNames) + for _, name := range sortedNames { + testFile.WriteString(fmt.Sprintf(" {\"%s\", %s},\n", name, name)) + } + testFile.WriteString(testFooter) + saveFile(path.Join(baseFolder, sectionName+"_test.go"), testFile.String()) + } +} + +func saveFile(pathFile, data string) { + err := maybe.WriteFile(pathFile, []byte(data), 0o644) + CheckErr(err) +} + +//nolint:gochecknoglobals +var testHeader = license + ` +package integration_test + +import ( + "bytes" + "testing" + + parser "github.com/haproxytech/client-native/v5/config-parser" + "github.com/haproxytech/client-native/v5/config-parser/options" +) + +func TestWholeConfigsSections(t *testing.T) { + t.Parallel() + tests := []struct { + Name, Config string + }{ +` + +//nolint:gochecknoglobals +var testFooter = ` } + for _, config := range tests { + t.Run(config.Name, func(t *testing.T) { + t.Parallel() + var buffer bytes.Buffer + buffer.WriteString(config.Config) + p, err := parser.New(options.Reader(&buffer)) + if err != nil { + t.Fatalf(err.Error()) + } + result := p.String() + if result != config.Config { + compare(t, config.Config, result) + t.Error("======== ORIGINAL =========") + t.Error(config.Config) + t.Error("======== RESULT ===========") + t.Error(result) + t.Error("===========================") + t.Fatalf("configurations does not match") + } + }) + } +} +` diff --git a/config-parser/generate/main.go b/config-parser/generate/main.go new file mode 100644 index 00000000..30fa020d --- /dev/null +++ b/config-parser/generate/main.go @@ -0,0 +1,63 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +import ( + "log" + "os" + "path" + "path/filepath" + "strings" + + "github.com/google/renameio/maybe" +) + +//nolint:gochecknoglobals +var configFile = ConfigFile{} + +func main() { + dir, err := filepath.Abs(filepath.Dir(os.Args[0])) + if err != nil { + log.Fatal(err) + } + if strings.HasSuffix(dir, "generate") { + dir, err = filepath.Abs(filepath.Dir(os.Args[0]) + "/..") + if err != nil { + log.Fatal(err) + } + } + if len(os.Args) > 1 { + dir = os.Args[1] + } + log.Println(dir) + + configFile.Section = map[string][]string{} + + generateTypes(dir, "") + generateTypesGeneric(dir) + generateTypesOther(dir) + // spoe + generateTypes(dir, "spoe/") + + filePath := path.Join(dir, "tests", "configs", "haproxy_generated.cfg.go") + res, err := GoFmt([]byte(configFile.String())) + CheckErr(err) + err = maybe.WriteFile(filePath, res, 0o644) + CheckErr(err) + + configFile.StringFiles(path.Join(dir, "tests", "integration")) +} diff --git a/config-parser/generate/misc.go b/config-parser/generate/misc.go new file mode 100644 index 00000000..17039ae2 --- /dev/null +++ b/config-parser/generate/misc.go @@ -0,0 +1,132 @@ +/* +Copyright 2022 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +import ( + "bytes" + _ "embed" + "fmt" + "go/format" + "log" + "os" + "strings" + "text/template" + "unicode" + + "github.com/google/renameio" +) + +const license = `// Code generated by go generate; DO NOT EDIT. +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +` + +type TemplateType uint8 + +const ( + TemplateTypeNormal TemplateType = 1 + TemplateTypeOther TemplateType = 2 + TemplateTypeTest TemplateType = 10 +) + +func fileExists(filePath string) bool { + _, err := os.Stat(filePath) + if !os.IsNotExist(err) { + log.Println("File " + filePath + " already exists") + } + return !os.IsNotExist(err) +} + +func cleanFileName(filename string) string { + return strings.ReplaceAll(filename, " ", "-") +} + +func CheckErr(err error) { + if err != nil { + log.Fatal(err) + } +} + +//go:embed normal.tmpl +var templateNormal []byte + +//go:embed others.tmpl +var templateOthers []byte + +//go:embed test.tmpl +var templateTest []byte + +func executeTemplate(tmplType TemplateType, data *Data, filePath string) { + var tmpl *template.Template + switch tmplType { + case TemplateTypeNormal: + tmpl = template.Must(template.New("").Parse(license + "\n" + string(templateNormal))) + case TemplateTypeOther: + tmpl = template.Must(template.New("").Parse(license + "\n" + string(templateOthers))) + case TemplateTypeTest: + tmpl = template.Must(template.New("").Parse(license + "\n" + string(templateTest))) + } + + log.Println(filePath) + var tpl bytes.Buffer + err := tmpl.Execute(&tpl, data) + CheckErr(err) + res, errFmt := GoFmt(tpl.Bytes()) + if errFmt != nil { + res = tpl.Bytes() + } + err = renameio.WriteFile(filePath, res, 0o666) + CheckErr(errFmt) + CheckErr(err) +} + +func GoFmt(input []byte) ([]byte, error) { + res, err := format.Source(input) + if err != nil { + return nil, fmt.Errorf("cmd.Run() failed with %w", err) + } + return res, nil +} + +func getNiceName(str string) string { + var res strings.Builder + for _, c := range str { + if unicode.IsLetter(c) || unicode.IsNumber(c) { + res.WriteRune(c) + } + } + strRes := res.String() + size := len(strRes) + if size > 32 { + size = 32 + } + strRes = strRes[0:size] + return strRes +} diff --git a/config-parser/generate/normal.tmpl b/config-parser/generate/normal.tmpl new file mode 100644 index 00000000..38edc521 --- /dev/null +++ b/config-parser/generate/normal.tmpl @@ -0,0 +1,230 @@ +{{- if .ModeOther}} +package {{ .Dir }} +{{- else }} +package parsers +{{- end }} + +import ( + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/{{ .DataDir }}types" +) + +{{- if not .NoInit }} + +func (p *{{ .StructName }}) Init() { +{{- if .ParserMultiple }} + p.data = []types.{{ .ParserType }}{} +{{- else }} + p.data = nil +{{- end }} + p.preComments = []string{} +} +{{- end }} + +{{- if not .NoName }} + +func (p *{{ .StructName }}) GetParserName() string { +{{- if .HasAlias}} + if p.Alias != "" { + return p.Alias + } +{{- end }} +{{- if .ModeOther}} + return p.Name +{{- else }} +{{- if eq .ParserSecondName "" }} + return "{{ .ParserName }}" +{{- else }} + return "{{ .ParserName }} {{ .ParserSecondName }}" +{{- end }} +{{- end }} +} +{{- end }} + +{{- if not .NoGet }} + +func (p *{{ .StructName }}) Get(createIfNotExist bool) (common.ParserData, error) { +{{- if .ParserMultiple }} + if len(p.data) == 0 && !createIfNotExist { + return nil, errors.ErrFetch + } +{{- else }} + if p.data == nil { + if createIfNotExist { + p.data = &types.{{ .ParserType }}{} + return p.data, nil + } + return nil, errors.ErrFetch + } +{{- end }} + return p.data, nil +} +{{- end }} + +func (p *{{ .StructName }}) GetPreComments() ([]string, error) { + return p.preComments, nil +} + +func (p *{{ .StructName }}) SetPreComments(preComments []string) { + p.preComments = preComments +} + +func (p *{{ .StructName }}) GetOne(index int) (common.ParserData, error) { +{{- if .ParserMultiple }} + if index < 0 || index >= len(p.data) { + return nil, errors.ErrFetch + } + return p.data[index], nil +{{- else }} + if index > 0 { + return nil, errors.ErrFetch + } + if p.data == nil { + return nil, errors.ErrFetch + } + return p.data, nil +{{- end }} +} + +func (p *{{ .StructName }}) Delete(index int) error { +{{- if .ParserMultiple }} + if index < 0 || index >= len(p.data) { + return errors.ErrFetch + } + copy(p.data[index:], p.data[index+1:]) +{{- if .IsInterface }} + p.data[len(p.data)-1] = nil +{{- else }} + p.data[len(p.data)-1] = types.{{ .ParserType }}{} +{{- end }} + p.data = p.data[:len(p.data)-1] + return nil +{{- else }} + p.Init() + return nil +{{- end }} +} + +func (p *{{ .StructName }}) Insert(data common.ParserData, index int) error { +{{- if .ParserMultiple }} + if data == nil { + return errors.ErrInvalidData + } + switch newValue := data.(type) { + case []types.{{ .ParserType }}: + p.data = newValue + case *types.{{ .ParserType }}: + if index > -1 { + if index > len(p.data) { + return errors.ErrIndexOutOfRange + } +{{- if .IsInterface }} + p.data = append(p.data, nil) +{{- else }} + p.data = append(p.data, types.{{ .ParserType }}{}) +{{- end }} + copy(p.data[index+1:], p.data[index:]) + p.data[index] = *newValue + } else { + p.data = append(p.data, *newValue) + } + case types.{{ .ParserType }}: + if index > -1 { + if index > len(p.data) { + return errors.ErrIndexOutOfRange + } +{{- if .IsInterface }} + p.data = append(p.data, nil) +{{- else }} + p.data = append(p.data, types.{{ .ParserType }}{}) +{{- end }} + copy(p.data[index+1:], p.data[index:]) + p.data[index] = newValue + } else { + p.data = append(p.data, newValue) + } + default: + return errors.ErrInvalidData + } + return nil +{{- else }} + return p.Set(data, index) +{{- end }} +} + +func (p *{{ .StructName }}) Set(data common.ParserData, index int) error { + if data == nil { + p.Init() + return nil + } +{{- if .ParserMultiple }} + switch newValue := data.(type) { + case []types.{{ .ParserType }}: + p.data = newValue + case *types.{{ .ParserType }}: + if index > -1 && index < len(p.data) { + p.data[index] = *newValue + } else if index == -1 { + p.data = append(p.data, *newValue) + } else { + return errors.ErrIndexOutOfRange + } + case types.{{ .ParserType }}: + if index > -1 && index < len(p.data) { + p.data[index] = newValue + } else if index == -1 { + p.data = append(p.data, newValue) + } else { + return errors.ErrIndexOutOfRange + } + default: + return errors.ErrInvalidData + } +{{- else }} + switch newValue := data.(type) { + case *types.{{ .ParserType }}: + p.data = newValue + case types.{{ .ParserType }}: + p.data = &newValue + default: + return errors.ErrInvalidData + } +{{- end }} + return nil +} + +func (p *{{ .StructName }}) PreParse(line string, parts []string, preComments []string, comment string) (string, error) { + changeState, err := p.Parse(line, parts, comment) + if err == nil && preComments != nil { + p.preComments = append(p.preComments, preComments...) + } + return changeState, err +} + +{{- if and .ParserMultiple (not .NoParse) }} + +func (p *{{ .StructName }}) Parse(line string, parts []string, comment string) (string, error) { +{{- if eq .ParserSecondName "" }} + if parts[0] == "{{ .ParserName }}" { +{{- else }} + if len(parts) > 1 && parts[0] == "{{ .ParserName }}" && parts[1] == "{{ .ParserSecondName }}" { +{{- end }} + data, err := p.parse(line, parts, comment) + if err != nil { + if _, ok := err.(*errors.ParseError); ok { + return "", err + } + return "", &errors.ParseError{Parser: "{{ .StructName }}", Line: line} + } + p.data = append(p.data, *data) + return "", nil + } + return "", &errors.ParseError{Parser: "{{ .StructName }}", Line: line} +} +{{- end }} + +func (p *{{ .StructName }}) ResultAll() ([]common.ReturnResultLine, []string, error) { + res, err := p.Result() + return res, p.preComments, err +} diff --git a/config-parser/generate/others.tmpl b/config-parser/generate/others.tmpl new file mode 100644 index 00000000..f16590dd --- /dev/null +++ b/config-parser/generate/others.tmpl @@ -0,0 +1,66 @@ +{{- if .ModeOther}} +package {{ .Dir }} +{{- else }} +package parsers +{{- end }} + +import ( + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/{{ .DataDir }}types" +) + +type {{ .StructName }} struct { + Name string + // Mode string + data []types.{{ .ParserType }} + preComments []string // comments that appear before the actual line +} + +{{- if not .NoInit }} + +func (p *{{ .StructName }}) Init() { +{{- if .ParserMultiple }} + p.Name = "{{ .ParserName }}" + p.data = []types.{{ .ParserType }}{} +{{- else }} + p.data = nil +{{- end }} + p.preComments = nil + // Following line forces compilation to fail: + Function not implemented! +} +{{- end }} + +func (h *{{ .StructName }} ) Parse(line string, parts []string, comment string) (string, error) { + return "", &errors.ParseError{Parser: parseErrorLines("{{ .ParserName }}"), Line: line} + + // Following line forces compilation to fail: + Function not implemented! +} + +func (h *{{ .StructName }} ) Result() ([]common.ReturnResultLine, error) { + if len(h.data) == 0 { + return nil, errors.ErrFetch + } + + result := make([]common.ReturnResultLine, len(h.data)) + for index, req := range h.data { + result[index] = common.ReturnResultLine{ + Data: "{{ .ParserName }}" + req.String(), + Comment: req.GetComment(), + } + } + return result, nil +} + +func parseErrorLines(s string) string { + var r string + parts := strings.Split(s, "-") + if len(parts) == 1 { + r = strings.Title(parts[0]) + } else { + r = strings.Title(parts[0]) + strings.Title(parts[1]) + } + return r + "Lines" +} diff --git a/config-parser/generate/test.tmpl b/config-parser/generate/test.tmpl new file mode 100644 index 00000000..22b10066 --- /dev/null +++ b/config-parser/generate/test.tmpl @@ -0,0 +1,188 @@ +package tests + +import ( + "fmt" + "strings" + "testing" + + "github.com/haproxytech/client-native/v5/config-parser/{{ .DataDir }}parsers{{- if .ModeOther}}/{{ .Dir }}{{- end }}" +) +{{ $StructName := .StructName }} +func Test{{ $StructName }}{{ .Dir }}(t *testing.T) { + tests := map[string]bool{ + {{- range $index, $val := .TestOKDefaults}} + `{{- $val -}}`: true, + {{- end }} + {{- range $index, $val := .TestOKFrontend}} + `{{- $val -}}`: true, + {{- end }} + {{- range $index, $val := .TestOKBackend}} + `{{- $val -}}`: true, + {{- end }} + {{- range $index, $val := .TestOK}} + "{{- $val -}}": true, + {{- end }} + {{- range $index, $val := .TestOKEscaped}} + `{{- $val -}}`: true, + {{- end }} + {{- range $index, $val := .TestFail}} + "{{- $val -}}": false, + {{- end }} + {{- range $index, $val := .TestFailEscaped}} + `{{- $val -}}`: false, + {{- end }} + } + {{- if .HasTable}} + testsTable := map[string]string{ + {{- range $index, $val := .TestTableOK}} + `{{- $val.Test -}}`: `{{- $val.Table -}}`, + {{- end }} + } + {{- end}} + parser := {{- if .ModeOther}} &{{ .Dir }}{{- else }} &parsers{{- end }}.{{ $StructName }}{} + for command, shouldPass := range tests { + t.Run(command, func(t *testing.T) { + line :=strings.TrimSpace(command) + lines := strings.SplitN(line,"\n", -1) + var err error + parser.Init() + if len(lines)> 1{ + for _,line = range(lines){ + line = strings.TrimSpace(line) + if err=ProcessLine(line, parser);err!=nil{ + break + } + } + }else{ + err = ProcessLine(line, parser) + } + if shouldPass { + if err != nil { + t.Errorf(err.Error()) + return + } + result, err := parser.Result() + if err != nil { + t.Errorf(err.Error()) + return + } + var returnLine string + if result[0].Comment == "" { + returnLine = result[0].Data + } else { + returnLine = fmt.Sprintf("%s # %s", result[0].Data, result[0].Comment) + } + if command != returnLine { + t.Errorf(fmt.Sprintf("error: has [%s] expects [%s]", returnLine, command)) + } + } else { + if err == nil { + t.Errorf(fmt.Sprintf("error: did not throw error for line [%s]", line)) + } + _, parseErr := parser.Result() + if parseErr == nil { + t.Errorf(fmt.Sprintf("error: did not throw error on result for line [%s]", line)) + } + } + }) + } + {{- if .HasTable}} + for command, expected := range testsTable { + t.Run(command, func(t *testing.T) { + line :=strings.TrimSpace(command) + lines := strings.SplitN(line,"\n", -1) + var err error + parser.Init() + if len(lines)> 1{ + for _,line = range(lines){ + line = strings.TrimSpace(line) + if err=ProcessLine(line, parser);err!=nil{ + break + } + } + }else{ + err = ProcessLine(line, parser) + } + if err != nil { + t.Errorf(err.Error()) + return + } + result, err := parser.Result() + if err != nil { + t.Errorf(err.Error()) + return + } + var returnLine string + if result[0].Comment == "" { + returnLine = result[0].Data + } else { + returnLine = fmt.Sprintf("%s # %s", result[0].Data, result[0].Comment) + } + if expected != returnLine { + t.Errorf(fmt.Sprintf("error: has [%s] expects [%s]", returnLine, expected)) + } + }) + } + {{- end}} +} + +{{- if .HasAlias}} + +func TestAlias{{ $StructName }}{{ .Dir }}(t *testing.T) { + tests := map[string]bool{ {{ $AliasName := .StructName }} + {{- range $index, $val := .TestAliasOK}} {{ $AliasName = $val.Alias }} + "{{- $val.Test -}}": true, + {{- end }} + {{- range $index, $val := .TestAliasFail}} + "{{- $val.Test -}}": false, + {{- end }} + } + parser := {{- if .ModeOther}} &{{ .Dir }}{{- else }} &parsers{{- end }}.{{ $StructName }}{Alias:"{{ $AliasName }}"} + for command, shouldPass := range tests { + t.Run(command, func(t *testing.T) { + line :=strings.TrimSpace(command) + lines := strings.SplitN(line,"\n", -1) + var err error + parser.Init() + if len(lines)> 1{ + for _,line = range(lines){ + line = strings.TrimSpace(line) + if err=ProcessLine(line, parser);err!=nil{ + break + } + } + }else{ + err = ProcessLine(line, parser) + } + if shouldPass { + if err != nil { + t.Errorf(err.Error()) + return + } + result, err := parser.Result() + if err != nil { + t.Errorf(err.Error()) + return + } + var returnLine string + if result[0].Comment == "" { + returnLine = result[0].Data + } else { + returnLine = fmt.Sprintf("%s # %s", result[0].Data, result[0].Comment) + } + if command != returnLine { + t.Errorf(fmt.Sprintf("error: has [%s] expects [%s]", returnLine, command)) + } + } else { + if err == nil { + t.Errorf(fmt.Sprintf("error: did not throw error for line [%s]", line)) + } + _, parseErr := parser.Result() + if parseErr == nil { + t.Errorf(fmt.Sprintf("error: did not throw error on result for line [%s]", line)) + } + } + }) + } +} +{{- end }} diff --git a/config-parser/generate/types-generic.go b/config-parser/generate/types-generic.go new file mode 100644 index 00000000..882bbf2c --- /dev/null +++ b/config-parser/generate/types-generic.go @@ -0,0 +1,150 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +import ( + "fmt" + "log" + "os" + "path" + "strings" + + "github.com/haproxytech/client-native/v5/config-parser/common" +) + +func generateTypesGeneric(dir string) { //nolint:gocognit + dat, err := os.ReadFile("types/types-generic.go") + if err != nil { + log.Println(err) + } + lines := common.StringSplitIgnoreEmpty(string(dat), '\n') + + parsers := map[string]*Data{} + parserData := &Data{} + for _, line := range lines { + if strings.HasPrefix(line, "//sections:") { + s := strings.Split(line, ":") + parserData.ParserSections = strings.Split(s[1], ",") + } + if strings.HasPrefix(line, "//no:sections") { + parserData.NoSections = true + } + if strings.HasPrefix(line, "//name:") { + data := common.StringSplitIgnoreEmpty(line, ':') + items := common.StringSplitIgnoreEmpty(data[1], ' ') + parserData.ParserName = data[1] + if len(items) > 1 { + parserData.ParserName = items[0] + parserData.ParserSecondName = items[1] + } + } + if strings.HasPrefix(line, "//no:init") { + parserData.NoInit = true + } + if strings.HasPrefix(line, "//no:name") { + parserData.NoName = true + } + if strings.HasPrefix(line, "//no:parse") { + parserData.NoParse = true + } + if strings.HasPrefix(line, `//test:quote_ok`) { + data := strings.SplitN(line, ":", 3) + parserData.TestOKEscaped = append(parserData.TestOKEscaped, data[2]) + } + if strings.HasPrefix(line, `//test:defaults-ok`) { + data := strings.SplitN(line, ":", 3) + parserData.TestOKDefaults = append(parserData.TestOKDefaults, data[2]) + } + if strings.HasPrefix(line, `//test:frontend-ok`) { + data := strings.SplitN(line, ":", 3) + parserData.TestOKFrontend = append(parserData.TestOKFrontend, data[2]) + } + if strings.HasPrefix(line, `//test:backend-ok`) { + data := strings.SplitN(line, ":", 3) + parserData.TestOKBackend = append(parserData.TestOKBackend, data[2]) + } + if strings.HasPrefix(line, "//test:ok") { + data := strings.SplitN(line, ":", 3) + parserData.TestOK = append(parserData.TestOK, data[2]) + } + if strings.HasPrefix(line, `//test:quote_fail`) { + data := strings.SplitN(line, ":", 3) + parserData.TestFailEscaped = append(parserData.TestFailEscaped, data[2]) + } + if strings.HasPrefix(line, "//test:fail") { + data := strings.SplitN(line, ":", 3) + parserData.TestFail = append(parserData.TestFail, data[2]) + } + if strings.HasPrefix(line, "//test:alias") { + data := strings.SplitN(line, ":", 5) + aliasTestData := AliasTestData{ + Alias: data[2], + Test: data[4], + } + switch data[3] { + case "ok": + parserData.TestAliasOK = append(parserData.TestAliasOK, aliasTestData) + case "fail": + parserData.TestAliasFail = append(parserData.TestAliasFail, aliasTestData) + default: + log.Fatalf("not able to process line %s", line) + } + } + if strings.HasPrefix(line, "//generate:type:") { + data := common.StringSplitIgnoreEmpty(line, ':') + parserData = &Data{} + parserData.StructName = data[2] + parsers[data[2]] = parserData + } + if strings.HasPrefix(line, "//has-alias:true") { + parserData.HasAlias = true + } + + if !strings.HasPrefix(line, "type ") { + continue + } + + if parserData.ParserName == "" { + parserData = &Data{} + continue + } + data := common.StringSplitIgnoreEmpty(line, ' ') + parserType := data[1] + + for _, parserData := range parsers { + parserData.ParserType = parserType + + filename := parserData.ParserName + if parserData.ParserSecondName != "" { + filename = fmt.Sprintf("%s %s", filename, parserData.ParserSecondName) + } + + filePath := path.Join(dir, "parsers", cleanFileName(filename)+"_generated.go") + executeTemplate(TemplateTypeNormal, parserData, filePath) + + parserData.TestFail = append(parserData.TestFail, "---") + parserData.TestFail = append(parserData.TestFail, "--- ---") + + filePath = path.Join(dir, "tests", cleanFileName(filename)+"_generated_test.go") + executeTemplate(TemplateTypeTest, parserData, filePath) + log.Println(filePath) + } + // configFile.AddParserData(parserData) + parsers = map[string]*Data{} + parserData = &Data{} + } +} diff --git a/config-parser/generate/types-normal.go b/config-parser/generate/types-normal.go new file mode 100644 index 00000000..dbe04548 --- /dev/null +++ b/config-parser/generate/types-normal.go @@ -0,0 +1,157 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +import ( + "fmt" + "log" + "os" + "path" + "strings" + + "github.com/haproxytech/client-native/v5/config-parser/common" +) + +func generateTypes(dir string, dataDir string) { //nolint:gocognit + dat, err := os.ReadFile(dataDir + "types/types.go") + if err != nil { + log.Println(err) + } + lines := common.StringSplitIgnoreEmpty(string(dat), '\n') + + parserData := Data{} + + for _, line := range lines { + parserData.DataDir = dataDir + if strings.HasPrefix(line, "//deprecated:") { + parserData.Deprecated = true + } + if strings.HasPrefix(line, "//sections:") { + s := strings.Split(line, ":") + parserData.ParserSections = strings.Split(s[1], ",") + } + if strings.HasPrefix(line, "//no:sections") { + parserData.NoSections = true + } + if strings.HasPrefix(line, "//name:") { + data := common.StringSplitIgnoreEmpty(line, ':') + items := common.StringSplitIgnoreEmpty(data[1], ' ') + parserData.ParserName = data[1] + if len(items) > 1 { + parserData.ParserName = items[0] + parserData.ParserSecondName = items[1] + } + } + if strings.HasPrefix(line, "//is:multiple") { + parserData.ParserMultiple = true + } + if strings.HasPrefix(line, "//no:init") { + parserData.NoInit = true + } + if strings.HasPrefix(line, "//no:name") { + parserData.NoName = true + } + if strings.HasPrefix(line, "//no:parse") { + parserData.NoParse = true + } + if strings.HasPrefix(line, `//test:quote_ok`) && !parserData.Deprecated { + data := strings.SplitN(line, ":", 3) + parserData.TestOKEscaped = append(parserData.TestOKEscaped, data[2]) + } + if strings.HasPrefix(line, `//test:"defaults-ok"`) && !parserData.Deprecated { + data := strings.SplitN(line, ":", 3) + parserData.TestOKDefaults = append(parserData.TestOKDefaults, data[2]) + } + if strings.HasPrefix(line, `//test:"frontend-ok"`) && !parserData.Deprecated { + data := strings.SplitN(line, ":", 3) + parserData.TestOKFrontend = append(parserData.TestOKFrontend, data[2]) + } + if strings.HasPrefix(line, `//test:"backend-ok"`) && !parserData.Deprecated { + data := strings.SplitN(line, ":", 3) + parserData.TestOKBackend = append(parserData.TestOKBackend, data[2]) + } + if strings.HasPrefix(line, "//test:ok") && !parserData.Deprecated { + data := strings.SplitN(line, ":", 3) + parserData.TestOK = append(parserData.TestOK, data[2]) + } + if strings.HasPrefix(line, `//test:quote_fail`) && !parserData.Deprecated { + data := strings.SplitN(line, ":", 3) + parserData.TestFailEscaped = append(parserData.TestFailEscaped, data[2]) + } + if strings.HasPrefix(line, "//test:fail") && !parserData.Deprecated { + data := strings.SplitN(line, ":", 3) + parserData.TestFail = append(parserData.TestFail, data[2]) + } + if strings.HasPrefix(line, "//test:expected-ok") && !parserData.Deprecated { + data := strings.SplitN(line, ":", 4) + tableTestData := TableTestData{ + Test: data[2], + Table: data[3], + } + parserData.TestTableOK = append(parserData.TestTableOK, tableTestData) + parserData.HasTable = true + } + if strings.HasPrefix(line, "//test:alias") { + data := strings.SplitN(line, ":", 5) + aliasTestData := AliasTestData{ + Alias: data[2], + Test: data[4], + } + switch data[3] { + case "ok": + parserData.TestAliasOK = append(parserData.TestAliasOK, aliasTestData) + case "fail": + parserData.TestAliasFail = append(parserData.TestAliasFail, aliasTestData) + default: + log.Fatalf("not able to process line %s", line) + } + } + if strings.HasPrefix(line, "//has-alias:true") { + parserData.HasAlias = true + } + + if !strings.HasPrefix(line, "type ") { + continue + } + + if parserData.ParserName == "" { + parserData = Data{} + continue + } + data := common.StringSplitIgnoreEmpty(line, ' ') + parserData.StructName = data[1] + parserData.ParserType = data[1] + + filename := parserData.ParserName + if parserData.ParserSecondName != "" { + filename = fmt.Sprintf("%s %s", filename, parserData.ParserSecondName) + } + + filePath := path.Join(dir, dataDir, "parsers", cleanFileName(filename)+"_generated.go") + executeTemplate(TemplateTypeNormal, &parserData, filePath) + + // parserData.TestFail = append(parserData.TestFail, "") parsers should not get empty line! + parserData.TestFail = append(parserData.TestFail, "---") + parserData.TestFail = append(parserData.TestFail, "--- ---") + + filePath = path.Join(dir, dataDir, "tests", cleanFileName(filename)+"_generated_test.go") + executeTemplate(TemplateTypeTest, &parserData, filePath) + + configFile.AddParserData(parserData) + parserData = Data{} + } +} diff --git a/config-parser/generate/types-other.go b/config-parser/generate/types-other.go new file mode 100644 index 00000000..c56c2c8c --- /dev/null +++ b/config-parser/generate/types-other.go @@ -0,0 +1,180 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +import ( + "fmt" + "log" + "os" + "path" + "strings" + + "github.com/haproxytech/client-native/v5/config-parser/common" +) + +func generateTypesOther(dir string) { //nolint:gocognit + dat, err := os.ReadFile("types/types-other.go") + if err != nil { + log.Println(err) + } + lines := common.StringSplitIgnoreEmpty(string(dat), '\n') + + parserData := Data{} + for _, line := range lines { + if strings.HasPrefix(line, "//sections:") { + s := strings.Split(line, ":") + parserData.ParserSections = strings.Split(s[1], ",") + } + if strings.HasPrefix(line, "//no:sections") { + parserData.NoSections = true + } + if strings.HasPrefix(line, "//name:") { + data := common.StringSplitIgnoreEmpty(line, ':') + items := common.StringSplitIgnoreEmpty(data[1], ' ') + parserData.ParserName = data[1] + if len(items) > 1 { + parserData.ParserName = items[0] + parserData.ParserSecondName = items[1] + } + } + if strings.HasPrefix(line, "//struct:name:") { + data := common.StringSplitIgnoreEmpty(line, ':') + parserData.StructName = data[2] + } + if strings.HasPrefix(line, "//dir:") { + data := common.StringSplitIgnoreEmpty(line, ':') + parserData.Dir = data[1] + } + if strings.HasPrefix(line, "//is:multiple") { + parserData.ParserMultiple = true + } + if strings.HasPrefix(line, "//no:init") { + parserData.NoInit = true + } + if strings.HasPrefix(line, "//no:name") { + parserData.NoName = true + } + if strings.HasPrefix(line, "//no:parse") { + parserData.NoParse = true + } + if strings.HasPrefix(line, "//is:interface") { + parserData.IsInterface = true + } + if strings.HasPrefix(line, "//parser:type:") { + data := common.StringSplitIgnoreEmpty(line, ':') + parserData.ParserTypeOverride = data[2] + } + if strings.HasPrefix(line, "//no:get") { + parserData.NoGet = true + } + if strings.HasPrefix(line, `//test:quote_ok`) { + data := strings.SplitN(line, ":", 3) + parserData.TestOKEscaped = append(parserData.TestOKEscaped, data[2]) + } + if strings.HasPrefix(line, `//test:defaults-ok`) { + data := strings.SplitN(line, ":", 3) + parserData.TestOKDefaults = append(parserData.TestOKDefaults, data[2]) + } + if strings.HasPrefix(line, `//test:frontend-ok`) { + data := strings.SplitN(line, ":", 3) + parserData.TestOKFrontend = append(parserData.TestOKFrontend, data[2]) + } + if strings.HasPrefix(line, `//test:backend-ok`) { + data := strings.SplitN(line, ":", 3) + parserData.TestOKBackend = append(parserData.TestOKBackend, data[2]) + } + if strings.HasPrefix(line, "//test:ok") { + data := strings.SplitN(line, ":", 3) + parserData.TestOK = append(parserData.TestOK, data[2]) + } + if strings.HasPrefix(line, `//test:quote_fail`) { + data := strings.SplitN(line, ":", 3) + parserData.TestFailEscaped = append(parserData.TestFailEscaped, data[2]) + } + if strings.HasPrefix(line, "//test:fail") { + data := strings.SplitN(line, ":", 3) + parserData.TestFail = append(parserData.TestFail, data[2]) + } + if strings.HasPrefix(line, "//test:alias") { + data := strings.SplitN(line, ":", 5) + aliasTestData := AliasTestData{ + Alias: data[2], + Test: data[4], + } + switch data[3] { + case "ok": + parserData.TestAliasOK = append(parserData.TestAliasOK, aliasTestData) + case "fail": + parserData.TestAliasFail = append(parserData.TestAliasFail, aliasTestData) + default: + log.Fatalf("not able to process line %s", line) + } + } + if strings.HasPrefix(line, "//test:skip") { + parserData.TestSkip = true + } + if strings.HasPrefix(line, "//has-alias:true") { + parserData.HasAlias = true + } + + if !strings.HasPrefix(line, "type ") { + continue + } + + if parserData.ParserName == "" { + parserData = Data{} + continue + } + data := common.StringSplitIgnoreEmpty(line, ' ') + if parserData.StructName == "" { + parserData.StructName = data[1] + } + parserData.ParserType = data[1] + if parserData.ParserTypeOverride != "" { + parserData.ParserType = parserData.ParserTypeOverride + } + + filename := parserData.ParserName + if parserData.ParserSecondName != "" { + filename = fmt.Sprintf("%s %s", filename, parserData.ParserSecondName) + } + + // Main parser file. + filePath := path.Join(dir, "parsers", parserData.Dir, cleanFileName(filename)+".go") + if !fileExists(filePath) { + parserData.ModeOther = true + executeTemplate(TemplateTypeOther, &parserData, filePath) + } + + // Generated parser file. + filePath = path.Join(dir, "parsers", parserData.Dir, cleanFileName(filename)+"_generated.go") + parserData.ModeOther = true + executeTemplate(TemplateTypeNormal, &parserData, filePath) + + if !parserData.TestSkip { + parserData.TestFail = append(parserData.TestFail, "---") + parserData.TestFail = append(parserData.TestFail, "--- ---") + dataDir := "" + + filePath = path.Join(dir, dataDir, "tests", cleanFileName(filename)+"_generated_test.go") + executeTemplate(TemplateTypeTest, &parserData, filePath) + } + + configFile.AddParserData(parserData) + parserData = Data{} + } +} diff --git a/config-parser/init.go b/config-parser/init.go new file mode 100644 index 00000000..0b93c83d --- /dev/null +++ b/config-parser/init.go @@ -0,0 +1,96 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package parser + +import ( + "sync" +) + +type ConfiguredParsers struct { + _ [0]int + State string + ActiveComments []string + ActiveSectionComments []string + Active *Parsers + Previous *Parsers + HasDefaultParser bool + Comments *Parsers + Defaults *Parsers + Global *Parsers + Frontend *Parsers + Backend *Parsers + Listen *Parsers + Resolver *Parsers + Userlist *Parsers + Peers *Parsers + Mailers *Parsers + Cache *Parsers + Program *Parsers + HTTPErrors *Parsers + Ring *Parsers + LogForward *Parsers + FCGIApp *Parsers + // spoe parsers + SPOEAgent *Parsers + SPOEGroup *Parsers + SPOEMessage *Parsers +} + +func (p *configParser) Init() { + if p.Options.Log { + p.Options.Logger.Debugf("%sinit", p.Options.LogPrefix) + } + p.initParserMaps() + for _, sections := range p.Parsers { + for _, parsers := range sections { + for _, parser := range parsers.Parsers { + parser.Init() + } + } + } +} + +func (p *configParser) initParserMaps() { + p.mutex = &sync.Mutex{} + p.lastDefaultsSectionName = "" + + p.Parsers = map[Section]map[string]*Parsers{} + + p.Parsers[Comments] = map[string]*Parsers{ + CommentsSectionName: p.getStartParser(), + } + + p.Parsers[Defaults] = map[string]*Parsers{} + + p.Parsers[Global] = map[string]*Parsers{ + GlobalSectionName: p.getGlobalParser(), + } + + p.Parsers[Frontends] = map[string]*Parsers{} + p.Parsers[Backends] = map[string]*Parsers{} + p.Parsers[Listen] = map[string]*Parsers{} + p.Parsers[Resolvers] = map[string]*Parsers{} + p.Parsers[UserList] = map[string]*Parsers{} + p.Parsers[Peers] = map[string]*Parsers{} + p.Parsers[Mailers] = map[string]*Parsers{} + p.Parsers[Cache] = map[string]*Parsers{} + p.Parsers[Program] = map[string]*Parsers{} + p.Parsers[HTTPErrors] = map[string]*Parsers{} + p.Parsers[Ring] = map[string]*Parsers{} + p.Parsers[LogForward] = map[string]*Parsers{} + p.Parsers[FCGIApp] = map[string]*Parsers{} +} diff --git a/config-parser/logger.go b/config-parser/logger.go new file mode 100644 index 00000000..91173f87 --- /dev/null +++ b/config-parser/logger.go @@ -0,0 +1,30 @@ +/* +Copyright 2021 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package parser + +import ( + "errors" +) + +func (p *configParser) SetLoggerState(active bool) error { + if p.Options.Logger == nil { + return errors.New("logger is not set") + } + p.Options.Logger.Debugf("%slogger set to state: %v", p.Options.LogPrefix, active) + p.Options.Log = active + return nil +} diff --git a/config-parser/options/configuration-data.go b/config-parser/options/configuration-data.go new file mode 100644 index 00000000..7fe4d2d6 --- /dev/null +++ b/config-parser/options/configuration-data.go @@ -0,0 +1,61 @@ +/* +Copyright 2021 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package options + +import ( + "io" + "strings" +) + +type filename struct { + Path string +} + +func (f filename) Set(p *Parser) error { + p.Path = f.Path + return nil +} + +// Reader takes path where configuration is stored +func Path(path string) ParserOption { + return filename{ + Path: path, + } +} + +type reader struct { + Reader io.Reader +} + +func (f reader) Set(p *Parser) error { + p.Reader = f.Reader + return nil +} + +// Reader takes io.Reader that will be used to parse data +func Reader(ioReader io.Reader) ParserOption { + return reader{ + Reader: ioReader, + } +} + +// String takes string that will be used to parse data +func String(configuration string) ParserOption { + return reader{ + Reader: strings.NewReader(configuration), + } +} diff --git a/config-parser/options/disable-unprocessed.go b/config-parser/options/disable-unprocessed.go new file mode 100644 index 00000000..7827d704 --- /dev/null +++ b/config-parser/options/disable-unprocessed.go @@ -0,0 +1,27 @@ +/* +Copyright 2021 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package options + +type disableUnProcessed struct{} + +func (u disableUnProcessed) Set(p *Parser) error { + p.DisableUnProcessed = true + return nil +} + +// DisableUnProcessed sets flag to disable catching lines that have no parser and to return error +var DisableUnProcessed = disableUnProcessed{} //nolint:gochecknoglobals diff --git a/config-parser/options/logger.go b/config-parser/options/logger.go new file mode 100644 index 00000000..55a09dbb --- /dev/null +++ b/config-parser/options/logger.go @@ -0,0 +1,46 @@ +/* +Copyright 2021 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package options + +import "github.com/haproxytech/go-logger" + +type logging struct { + log logger.Format + prefix string +} + +func (u logging) Set(p *Parser) error { + p.Logger = u.log + p.Log = true + if u.prefix != "" { + p.LogPrefix = u.prefix + " " + } + return nil +} + +// Logger takes acceptable logger that will be used for logging +func Logger(log logger.Format) ParserOption { + return LoggerWithPrefix(log, "") +} + +// Logger takes acceptable logger that will be used for logging, prefix can be defined to distinguish log messages generated in this package +func LoggerWithPrefix(log logger.Format, prefix string) ParserOption { + return logging{ + log: log, + prefix: prefix, + } +} diff --git a/config-parser/options/no-named-defaults-from.go b/config-parser/options/no-named-defaults-from.go new file mode 100644 index 00000000..8b3a4265 --- /dev/null +++ b/config-parser/options/no-named-defaults-from.go @@ -0,0 +1,27 @@ +/* +Copyright 2021 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package options + +type noNamedDefaultsFrom struct{} + +func (u noNamedDefaultsFrom) Set(p *Parser) error { + p.NoNamedDefaultsFrom = true + return nil +} + +// NoNamedDefaultsFrom sets flag to disable named defaults from in section +var NoNamedDefaultsFrom = noNamedDefaultsFrom{} //nolint:gochecknoglobals diff --git a/config-parser/options/options.go b/config-parser/options/options.go new file mode 100644 index 00000000..46a3027e --- /dev/null +++ b/config-parser/options/options.go @@ -0,0 +1,40 @@ +/* +Copyright 2021 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package options + +import ( + "io" + + "github.com/haproxytech/go-logger" +) + +type Parser struct { + Path string + Reader io.Reader + Logger logger.Format // we always will have p.Options.LogPrefix + UseV2HTTPCheck bool + UseMd5Hash bool + UseListenSectionParsers bool + DisableUnProcessed bool + Log bool + LogPrefix string + NoNamedDefaultsFrom bool +} + +type ParserOption interface { + Set(p *Parser) error +} diff --git a/config-parser/options/use-MD5-hash.go b/config-parser/options/use-MD5-hash.go new file mode 100644 index 00000000..037f2002 --- /dev/null +++ b/config-parser/options/use-MD5-hash.go @@ -0,0 +1,27 @@ +/* +Copyright 2021 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package options + +type useMd5Hash struct{} + +func (u useMd5Hash) Set(p *Parser) error { + p.UseMd5Hash = true + return nil +} + +// UseMd5Hash sets flag to use md5 hash +var UseMd5Hash = useMd5Hash{} //nolint:gochecknoglobals diff --git a/config-parser/options/use-V2HTTPCheck.go b/config-parser/options/use-V2HTTPCheck.go new file mode 100644 index 00000000..f8bfbd7d --- /dev/null +++ b/config-parser/options/use-V2HTTPCheck.go @@ -0,0 +1,27 @@ +/* +Copyright 2021 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package options + +type useV2HTTPCheck struct{} + +func (u useV2HTTPCheck) Set(p *Parser) error { + p.UseV2HTTPCheck = true + return nil +} + +// UseV2HTTPCheck sets flag to use deprecated HTTPCheck +var UseV2HTTPCheck = useV2HTTPCheck{} //nolint:gochecknoglobals diff --git a/config-parser/options/use-listen-section-parsers.go b/config-parser/options/use-listen-section-parsers.go new file mode 100644 index 00000000..42cb2577 --- /dev/null +++ b/config-parser/options/use-listen-section-parsers.go @@ -0,0 +1,27 @@ +/* +Copyright 2021 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package options + +type useListenSectionParsers struct{} + +func (u useListenSectionParsers) Set(p *Parser) error { + p.UseListenSectionParsers = true + return nil +} + +// UseListenSectionParsers sets flag to use listen section parser +var UseListenSectionParsers = useListenSectionParsers{} //nolint:gochecknoglobals diff --git a/config-parser/params/balance-params.go b/config-parser/params/balance-params.go new file mode 100644 index 00000000..4574d527 --- /dev/null +++ b/config-parser/params/balance-params.go @@ -0,0 +1,238 @@ +package params + +import ( + "strconv" + "strings" + + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" +) + +type BalanceParams interface { + String() string + Parse(parts []string) (BalanceParams, error) +} + +type BalanceURI struct { + Depth int64 + Len int64 + Whole bool + PathOnly bool +} + +func (b *BalanceURI) String() string { + var result strings.Builder + if b.Depth > 0 { + result.WriteString(" depth ") + result.WriteString(strconv.FormatInt(b.Depth, 10)) + } + if b.Len > 0 { + result.WriteString(" len ") + result.WriteString(strconv.FormatInt(b.Len, 10)) + } + if b.Whole { + result.WriteString(" whole") + } + if b.PathOnly { + result.WriteString(" path-only") + } + return result.String() +} + +func (b *BalanceURI) Parse(parts []string) (BalanceParams, error) { + var err error + if len(parts) > 0 { + + for i := 0; i < len(parts); i++ { + arg := parts[i] + + switch arg { + case "path-only": + b.PathOnly = true + case "whole": + b.Whole = true + case "len": + if i+1 < len(parts) { + i++ + if b.Len, err = strconv.ParseInt(parts[i], 10, 64); err != nil { + return nil, &errors.ParseError{Parser: "Balance", Message: err.Error()} + } + } + case "depth": + if i+1 < len(parts) { + i++ + if b.Depth, err = strconv.ParseInt(parts[i], 10, 64); err != nil { + return nil, &errors.ParseError{Parser: "Balance", Message: err.Error()} + } + } + } + } + return b, nil + } + return nil, errors.ErrInvalidData +} + +type BalanceURLParam struct { + Param string + CheckPost int64 + MaxWait int64 +} + +func (u *BalanceURLParam) String() string { + var result strings.Builder + if u.Param != "" { + result.WriteString(" ") + result.WriteString(u.Param) + } + if u.CheckPost > 0 { + result.WriteString(" check_post ") + result.WriteString(strconv.FormatInt(u.CheckPost, 10)) + } + if u.MaxWait > 0 { + result.WriteString(" max_wait ") + result.WriteString(strconv.FormatInt(u.MaxWait, 10)) + } + return result.String() +} + +func (u *BalanceURLParam) Parse(parts []string) (BalanceParams, error) { + var err error + if len(parts) > 0 { + + for index := 1; index < len(parts); index++ { + arg := parts[index] + + switch arg { + case "check_post": + if index+1 < len(parts) { + index++ + if u.CheckPost, err = strconv.ParseInt(parts[index], 10, 64); err != nil { + return nil, &errors.ParseError{Parser: "Balance", Message: err.Error()} + } + } + case "max_wait": + if index+1 < len(parts) { + index++ + if u.MaxWait, err = strconv.ParseInt(parts[index], 10, 64); err != nil { + return nil, &errors.ParseError{Parser: "Balance", Message: err.Error()} + } + } + default: + if index == 1 { + u.Param = arg + } + } + } + return u, nil + } + return nil, errors.ErrInvalidData +} + +type BalanceHdr struct { + Name string + UseDomainOnly bool +} + +func (h *BalanceHdr) String() string { + var result strings.Builder + if h.Name != "" { + result.WriteString("(") + result.WriteString(h.Name) + result.WriteString(")") + } + if h.UseDomainOnly { + result.WriteString(" use_domain_only") + } + return result.String() +} + +func (h *BalanceHdr) Parse(parts []string) (BalanceParams, error) { + if len(parts) > 0 { + split := common.StringSplitIgnoreEmpty(parts[0], '(', ')') + if len(split) < 2 { + return nil, errors.ErrInvalidData + } + h.Name = split[1] + } + if len(parts) > 1 { + if parts[1] != "use_domain_only" { + return nil, errors.ErrInvalidData + } + h.UseDomainOnly = true + } + return h, nil +} + +type BalanceRandom struct { + Draws int64 +} + +func (h *BalanceRandom) String() string { + var result strings.Builder + if h.Draws > 0 { + result.WriteString("(") + result.WriteString(strconv.FormatInt(h.Draws, 10)) + result.WriteString(")") + } + return result.String() +} + +func (h *BalanceRandom) Parse(parts []string) (BalanceParams, error) { + var err error + if len(parts) > 0 { + split := common.StringSplitIgnoreEmpty(parts[0], '(', ')') + if len(split) < 2 { + return nil, errors.ErrInvalidData + } + + if h.Draws, err = strconv.ParseInt(split[1], 10, 64); err != nil { + return nil, &errors.ParseError{Parser: "Balance", Message: err.Error()} + } + } + return h, nil +} + +type BalanceRdpCookie struct { + Name string +} + +func (r *BalanceRdpCookie) String() string { + var result strings.Builder + if r.Name != "" { + result.WriteString("(") + result.WriteString(r.Name) + result.WriteString(")") + } + return result.String() +} + +func (r *BalanceRdpCookie) Parse(parts []string) (BalanceParams, error) { + if len(parts) > 0 { + split := common.StringSplitIgnoreEmpty(parts[0], '(', ')') + if len(split) < 2 { + return nil, errors.ErrInvalidData + } + + r.Name = split[1] + } + return r, nil +} + +type BalanceHash struct { + Expression string +} + +func (r *BalanceHash) String() string { + var result strings.Builder + result.WriteString(" ") + result.WriteString(r.Expression) + return result.String() +} + +func (r *BalanceHash) Parse(parts []string) (BalanceParams, error) { + if len(parts) < 2 { + return nil, &errors.ParseError{Parser: "Balance", Message: "hash missing expression"} + } + r.Expression = strings.Join(parts[1:], " ") + return r, nil +} diff --git a/config-parser/params/bind-errors.go b/config-parser/params/bind-errors.go new file mode 100644 index 00000000..cbf9be1e --- /dev/null +++ b/config-parser/params/bind-errors.go @@ -0,0 +1,54 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package params + +import "fmt" + +type ErrParseBindOption interface { + Error() string +} + +type ErrParseServerOption interface { + Error() string +} + +// NotFoundError struct for creating parse errors +type NotFoundError struct { + Have string + Want string +} + +func (e *NotFoundError) Error() string { + return fmt.Sprintf("error: have [%s] want [%s]", e.Have, e.Want) +} + +// ParseError struct for creating parse errors +type NotEnoughParamsError struct{} + +func (e *NotEnoughParamsError) Error() string { + return "error: not enough params" +} + +// NotAllowedValuesError struct for allowed values errors +type NotAllowedValuesError struct { + Have string + Want []string +} + +func (e *NotAllowedValuesError) Error() string { + return "error: values not allowed" +} diff --git a/config-parser/params/bind-options.go b/config-parser/params/bind-options.go new file mode 100644 index 00000000..583c02f7 --- /dev/null +++ b/config-parser/params/bind-options.go @@ -0,0 +1,288 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package params + +import ( + "fmt" + "slices" + "strings" +) + +// BindOption ... +type BindOption interface { + Parse(options []string, currentIndex int) (int, error) + Valid() bool + String() string +} + +// BindOptionWord ... +type BindOptionWord struct { + Name string +} + +// Parse ... +func (b *BindOptionWord) Parse(options []string, currentIndex int) (int, error) { + if currentIndex < len(options) { + if options[currentIndex] == b.Name { + return 1, nil + } + return 0, &NotFoundError{Have: options[currentIndex], Want: b.Name} + } + return 0, &NotEnoughParamsError{} +} + +// Valid ... +func (b *BindOptionWord) Valid() bool { + return b.Name != "" +} + +// String ... +func (b *BindOptionWord) String() string { + return b.Name +} + +// BindOptionDoubleWord ... +type BindOptionDoubleWord struct { + Name string + Value string +} + +// Parse ... +func (b *BindOptionDoubleWord) Parse(options []string, currentIndex int) (int, error) { + if currentIndex+1 < len(options) { + if options[currentIndex] == b.Name && b.Value == options[currentIndex+1] { + return 2, nil + } + return 0, &NotFoundError{ + Have: fmt.Sprintf("%s %s", options[currentIndex], options[currentIndex]), + Want: fmt.Sprintf("%s %s", b.Name, b.Value), + } + } + return 0, &NotEnoughParamsError{} +} + +// Valid ... +func (b *BindOptionDoubleWord) Valid() bool { + return b.Name != "" && b.Value != "" +} + +// String ... +func (b *BindOptionDoubleWord) String() string { + if b.Name == "" || b.Value == "" { + return "" + } + return fmt.Sprintf("%s %s", b.Name, b.Value) +} + +// BindOptionValue ... +type BindOptionValue struct { + Name string + Value string +} + +// BindOptionValueValidation ... +type BindOptionValueValidation struct { + AllowedValues []string +} + +//nolint:gochecknoglobals +var bindOptionValuesValidation = map[string]BindOptionValueValidation{ + "quic-cc-algo": { + AllowedValues: []string{"cubic", "newreno"}, + }, + "quic-socket": { + AllowedValues: []string{"connection", "listener"}, + }, +} + +// Parse ... +func (b *BindOptionValue) Parse(options []string, currentIndex int) (int, error) { + if currentIndex+1 < len(options) { + if options[currentIndex] == b.Name { + b.Value = options[currentIndex+1] + if optionValuesValidation, ok := bindOptionValuesValidation[options[currentIndex]]; ok { + if !slices.Contains(optionValuesValidation.AllowedValues, b.Value) { + return 0, &NotAllowedValuesError{ + Have: options[currentIndex+1], + Want: optionValuesValidation.AllowedValues, + } + } + } + return 2, nil + } + return 0, &NotFoundError{Have: options[currentIndex], Want: b.Name} + } + return 0, &NotEnoughParamsError{} +} + +// Valid ... +func (b *BindOptionValue) Valid() bool { + return b.Value != "" +} + +// String ... +func (b *BindOptionValue) String() string { + if b.Name == "" || b.Value == "" { + return "" + } + return fmt.Sprintf("%s %s", b.Name, b.Value) +} + +func getBindOptions() []BindOption { + return []BindOption{ + &BindOptionWord{Name: "accept-proxy"}, + &BindOptionWord{Name: "allow-0rtt"}, + &BindOptionWord{Name: "defer-accept"}, + &BindOptionWord{Name: "force-sslv3"}, + &BindOptionWord{Name: "force-tlsv10"}, + &BindOptionWord{Name: "force-tlsv11"}, + &BindOptionWord{Name: "force-tlsv12"}, + &BindOptionWord{Name: "force-tlsv13"}, + &BindOptionWord{Name: "generate-certificates"}, + &BindOptionWord{Name: "no-alpn"}, + &BindOptionWord{Name: "no-ca-names"}, + &BindOptionWord{Name: "no-sslv3"}, + &BindOptionWord{Name: "no-tls-tickets"}, + &BindOptionWord{Name: "no-tlsv10"}, + &BindOptionWord{Name: "no-tlsv11"}, + &BindOptionWord{Name: "no-tlsv12"}, + &BindOptionWord{Name: "no-tlsv13"}, + &BindOptionWord{Name: "prefer-client-ciphers"}, + &BindOptionWord{Name: "ssl"}, + &BindOptionWord{Name: "strict-sni"}, + &BindOptionWord{Name: "tfo"}, + &BindOptionWord{Name: "transparent"}, + &BindOptionWord{Name: "v4v6"}, + &BindOptionWord{Name: "v6only"}, + &BindOptionWord{Name: "quic-force-retry"}, + + &BindOptionDoubleWord{Name: "expose-fd", Value: "listeners"}, + + &BindOptionValue{Name: "accept-netscaler-cip"}, + &BindOptionValue{Name: "alpn"}, + &BindOptionValue{Name: "backlog"}, + &BindOptionValue{Name: "curves"}, + &BindOptionValue{Name: "ecdhe"}, + &BindOptionValue{Name: "ca-file"}, + &BindOptionValue{Name: "ca-ignore-err"}, + &BindOptionValue{Name: "ca-sign-file"}, + &BindOptionValue{Name: "ca-sign-pass"}, + &BindOptionValue{Name: "ca-verify-file"}, + &BindOptionValue{Name: "ciphers"}, + &BindOptionValue{Name: "ciphersuites"}, + &BindOptionValue{Name: "client-sigalgs"}, + &BindOptionValue{Name: "crl-file"}, + &BindOptionValue{Name: "crt"}, + &BindOptionValue{Name: "crt-ignore-err"}, + &BindOptionValue{Name: "crt-list"}, + &BindOptionValue{Name: "gid"}, + &BindOptionValue{Name: "group"}, + &BindOptionValue{Name: "id"}, + &BindOptionValue{Name: "interface"}, + &BindOptionValue{Name: "level"}, + &BindOptionValue{Name: "severity-output"}, + &BindOptionValue{Name: "maxconn"}, + &BindOptionValue{Name: "mode"}, + &BindOptionValue{Name: "mss"}, + &BindOptionValue{Name: "name"}, + &BindOptionValue{Name: "namespace"}, + &BindOptionValue{Name: "nice"}, + &BindOptionValue{Name: "npn"}, + &BindOptionValue{Name: "ocsp-update"}, + &BindOptionValue{Name: "process"}, + &BindOptionValue{Name: "proto"}, + &BindOptionValue{Name: "sigalgs"}, + &BindOptionValue{Name: "ssl-max-ver"}, + &BindOptionValue{Name: "ssl-min-ver"}, + &BindOptionValue{Name: "tcp-ut"}, + &BindOptionValue{Name: "thread"}, + &BindOptionValue{Name: "tls-ticket-keys"}, + &BindOptionValue{Name: "uid"}, + &BindOptionValue{Name: "user"}, + &BindOptionValue{Name: "verify"}, + &BindOptionValue{Name: "quic-cc-algo"}, + &BindOptionValue{Name: "quic-socket"}, + &BindOptionValue{Name: "nbconn"}, + } +} + +// Parse ... +func ParseBindOptions(options []string) ([]BindOption, error) { + result := []BindOption{} + currentIndex := 0 + for currentIndex < len(options) { + found := false + for _, parser := range getBindOptions() { + if size, err := parser.Parse(options, currentIndex); err == nil { + result = append(result, parser) + found = true + currentIndex += size + } else if err.Error() == "error: values not allowed" { + return nil, err + } + } + if !found { + currentIndex++ + } + } + return result, nil +} + +func BindOptionsString(options []BindOption) string { + var sb strings.Builder + first := true + for _, parser := range options { + if parser.Valid() { + if !first { + sb.WriteString(" ") + } else { + first = false + } + sb.WriteString(parser.String()) + } + } + return sb.String() +} + +// CreateBindOptionWord creates valid one word value +func CreateBindOptionWord(name string) (BindOptionWord, ErrParseBindOption) { + b := BindOptionWord{ + Name: name, + } + _, err := b.Parse([]string{name}, 0) + return b, err +} + +// CreateBindOptionDoubleWord creates valid two word value +func CreateBindOptionDoubleWord(name1 string, name2 string) (BindOptionDoubleWord, ErrParseBindOption) { + b := BindOptionDoubleWord{ + Name: name1, + Value: name2, + } + _, err := b.Parse([]string{name1, name2}, 0) + return b, err +} + +// CreateBindOptionValue creates valid option with value +func CreateBindOptionValue(name string, value string) (BindOptionValue, ErrParseBindOption) { + b := BindOptionValue{ + Name: name, + Value: value, + } + _, err := b.Parse([]string{name, value}, 0) + return b, err +} diff --git a/config-parser/params/dgram-bind-options.go b/config-parser/params/dgram-bind-options.go new file mode 100644 index 00000000..51c89560 --- /dev/null +++ b/config-parser/params/dgram-bind-options.go @@ -0,0 +1,73 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package params + +import ( + "strings" +) + +// DgramBindOption ... +type DgramBindOption interface { + Parse(options []string, currentIndex int) (int, error) + Valid() bool + String() string +} + +func getDgramBindOptions() []DgramBindOption { + return []DgramBindOption{ + &BindOptionWord{Name: "transparent"}, + &BindOptionValue{Name: "interface"}, + &BindOptionValue{Name: "namespace"}, + &BindOptionValue{Name: "name"}, + } +} + +// Parse ... +func ParseDgramBindOptions(options []string) []DgramBindOption { + result := []DgramBindOption{} + currentIndex := 0 + for currentIndex < len(options) { + found := false + for _, parser := range getDgramBindOptions() { + if size, err := parser.Parse(options, currentIndex); err == nil { + result = append(result, parser) + found = true + currentIndex += size + } + } + if !found { + currentIndex++ + } + } + return result +} + +func DgramBindOptionsString(options []DgramBindOption) string { + var sb strings.Builder + first := true + for _, parser := range options { + if parser.Valid() { + if !first { + sb.WriteString(" ") + } else { + first = false + } + sb.WriteString(parser.String()) + } + } + return sb.String() +} diff --git a/config-parser/params/persist-params.go b/config-parser/params/persist-params.go new file mode 100644 index 00000000..122a1080 --- /dev/null +++ b/config-parser/params/persist-params.go @@ -0,0 +1,38 @@ +package params + +import ( + "strings" + + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" +) + +type PersistParams interface { + String() string + Parse(parts []string) (PersistParams, error) +} + +type PersistRdpCookie struct { + Name string +} + +func (r *PersistRdpCookie) String() string { + var result strings.Builder + if r.Name != "" { + result.WriteString("(") + result.WriteString(r.Name) + result.WriteString(")") + } + return result.String() +} + +func (r *PersistRdpCookie) Parse(parts []string) (PersistParams, error) { + if len(parts) > 0 { + split := common.StringSplitIgnoreEmpty(parts[0], '(', ')') + if len(split) < 2 { + return nil, errors.ErrInvalidData + } + r.Name = split[1] + } + return r, nil +} diff --git a/config-parser/params/server-options.go b/config-parser/params/server-options.go new file mode 100644 index 00000000..2c458713 --- /dev/null +++ b/config-parser/params/server-options.go @@ -0,0 +1,335 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package params + +import ( + "fmt" + "strings" +) + +// ServerOption ... +type ServerOption interface { + Parse(options []string, currentIndex int) (int, error) + Valid() bool + String() string +} + +// ServerOptionWord ... +type ServerOptionWord struct { + Name string +} + +// Parse ... +func (b *ServerOptionWord) Parse(options []string, currentIndex int) (int, error) { + if currentIndex < len(options) { + if options[currentIndex] == b.Name { + return 1, nil + } + return 0, &NotFoundError{Have: options[currentIndex], Want: b.Name} + } + return 0, &NotEnoughParamsError{} +} + +// Valid ... +func (b *ServerOptionWord) Valid() bool { + return b.Name != "" +} + +// String ... +func (b *ServerOptionWord) String() string { + return b.Name +} + +// ServerOptionDoubleWord ... +type ServerOptionDoubleWord struct { + Name string + Value string +} + +// Parse ... +func (b *ServerOptionDoubleWord) Parse(options []string, currentIndex int) (int, error) { + if currentIndex+1 < len(options) { + if options[currentIndex] == b.Name && b.Value == options[currentIndex+1] { + return 2, nil + } + return 0, &NotFoundError{ + Have: fmt.Sprintf("%s %s", options[currentIndex], options[currentIndex]), + Want: fmt.Sprintf("%s %s", b.Name, b.Value), + } + } + return 0, &NotEnoughParamsError{} +} + +// Valid ... +func (b *ServerOptionDoubleWord) Valid() bool { + return b.Name != "" && b.Value != "" +} + +// String ... +func (b *ServerOptionDoubleWord) String() string { + if b.Name == "" || b.Value == "" { + return "" + } + return fmt.Sprintf("%s %s", b.Name, b.Value) +} + +// ServerOptionValue ... +type ServerOptionValue struct { + Name string + Value string +} + +// Parse ... +func (b *ServerOptionValue) Parse(options []string, currentIndex int) (int, error) { + if currentIndex+1 < len(options) { + if options[currentIndex] == b.Name { + b.Value = options[currentIndex+1] + return 2, nil + } + return 0, &NotFoundError{Have: options[currentIndex], Want: b.Name} + } + return 0, &NotEnoughParamsError{} +} + +// Valid ... +func (b *ServerOptionValue) Valid() bool { + return b.Value != "" +} + +// String ... +func (b *ServerOptionValue) String() string { + if b.Name == "" || b.Value == "" { + return "" + } + return fmt.Sprintf("%s %s", b.Name, b.Value) +} + +type ServerOptionIDValue struct { + ID string + Name string + Value string +} + +// Parse ... +func (b *ServerOptionIDValue) Parse(options []string, currentIndex int) (int, error) { + if currentIndex+1 < len(options) { + if strings.HasPrefix(options[currentIndex], fmt.Sprintf("%s(", b.Name)) { + words := strings.Split(options[currentIndex], "(") + if len(words) != 2 { + return 0, &NotEnoughParamsError{} + } + if !strings.HasSuffix(words[1], ")") { + return 0, &NotEnoughParamsError{} + } + b.ID = words[1][:len(words[1])-1] + b.Value = options[currentIndex+1] + return 2, nil + } + return 0, &NotFoundError{Have: options[currentIndex], Want: b.Name} + } + return 0, &NotEnoughParamsError{} +} + +// Valid ... +func (b *ServerOptionIDValue) Valid() bool { + return b.Value != "" && b.ID != "" +} + +// String ... +func (b *ServerOptionIDValue) String() string { + if b.Name == "" || b.ID == "" || b.Value == "" { + return "" + } + return fmt.Sprintf("%s(%s) %s", b.Name, b.ID, b.Value) +} + +func getServerOptions() []ServerOption { + return []ServerOption{ + &ServerOptionWord{Name: "agent-check"}, + &ServerOptionWord{Name: "allow-0rtt"}, + &ServerOptionWord{Name: "backup"}, + &ServerOptionWord{Name: "check"}, + &ServerOptionWord{Name: "check-send-proxy"}, + &ServerOptionWord{Name: "check-ssl"}, + &ServerOptionWord{Name: "check-via-socks4"}, + &ServerOptionWord{Name: "disabled"}, + &ServerOptionWord{Name: "enabled"}, + &ServerOptionWord{Name: "force-sslv3"}, + &ServerOptionWord{Name: "force-tlsv10"}, + &ServerOptionWord{Name: "force-tlsv11"}, + &ServerOptionWord{Name: "force-tlsv12"}, + &ServerOptionWord{Name: "force-tlsv13"}, + &ServerOptionWord{Name: "no-agent-check"}, + &ServerOptionWord{Name: "no-backup"}, + &ServerOptionWord{Name: "no-check"}, + &ServerOptionWord{Name: "no-check-ssl"}, + &ServerOptionWord{Name: "no-send-proxy"}, + &ServerOptionWord{Name: "no-send-proxy-v2"}, + &ServerOptionWord{Name: "no-send-proxy-v2-ssl"}, + &ServerOptionWord{Name: "no-send-proxy-v2-ssl-cn"}, + &ServerOptionWord{Name: "no-ssl"}, + &ServerOptionWord{Name: "no-ssl-reuse"}, + &ServerOptionWord{Name: "no-sslv3"}, + &ServerOptionWord{Name: "no-tls-tickets"}, + &ServerOptionWord{Name: "no-tlsv10"}, + &ServerOptionWord{Name: "no-tlsv11"}, + &ServerOptionWord{Name: "no-tlsv12"}, + &ServerOptionWord{Name: "no-tlsv13"}, + &ServerOptionWord{Name: "no-verifyhost"}, + &ServerOptionWord{Name: "no-tfo"}, + &ServerOptionWord{Name: "non-stick"}, + &ServerOptionWord{Name: "send-proxy"}, + &ServerOptionWord{Name: "send-proxy-v2"}, + &ServerOptionWord{Name: "send-proxy-v2-ssl"}, + &ServerOptionWord{Name: "send-proxy-v2-ssl-cn"}, + &ServerOptionWord{Name: "ssl"}, + &ServerOptionWord{Name: "ssl-reuse"}, + &ServerOptionWord{Name: "stick"}, + &ServerOptionWord{Name: "tfo"}, + &ServerOptionWord{Name: "tls-tickets"}, + &ServerOptionValue{Name: "addr"}, + &ServerOptionValue{Name: "agent-send"}, + &ServerOptionValue{Name: "agent-inter"}, + &ServerOptionValue{Name: "agent-addr"}, + &ServerOptionValue{Name: "agent-port"}, + &ServerOptionValue{Name: "alpn"}, + &ServerOptionValue{Name: "ca-file"}, + &ServerOptionValue{Name: "check-alpn"}, + &ServerOptionValue{Name: "check-proto"}, + &ServerOptionValue{Name: "check-sni"}, + &ServerOptionValue{Name: "ciphers"}, + &ServerOptionValue{Name: "ciphersuites"}, + &ServerOptionValue{Name: "client-sigalgs"}, + &ServerOptionValue{Name: "cookie"}, + &ServerOptionValue{Name: "crl-file"}, + &ServerOptionValue{Name: "crt"}, + &ServerOptionValue{Name: "curves"}, + &ServerOptionValue{Name: "error-limit"}, + &ServerOptionValue{Name: "fall"}, + &ServerOptionValue{Name: "id"}, + &ServerOptionValue{Name: "init-addr"}, + &ServerOptionValue{Name: "inter"}, + &ServerOptionValue{Name: "fastinter"}, + &ServerOptionValue{Name: "downinter"}, + &ServerOptionValue{Name: "log-proto"}, + &ServerOptionValue{Name: "maxconn"}, + &ServerOptionValue{Name: "maxqueue"}, + &ServerOptionValue{Name: "max-reuse"}, + &ServerOptionValue{Name: "minconn"}, + &ServerOptionValue{Name: "namespace"}, + &ServerOptionValue{Name: "npn"}, + &ServerOptionValue{Name: "observe"}, + &ServerOptionValue{Name: "on-error"}, + &ServerOptionValue{Name: "on-marked-down"}, + &ServerOptionValue{Name: "on-marked-up"}, + &ServerOptionValue{Name: "pool-max-conn"}, + &ServerOptionValue{Name: "pool-purge-delay"}, + &ServerOptionValue{Name: "port"}, + &ServerOptionValue{Name: "proto"}, + &ServerOptionValue{Name: "redir"}, + &ServerOptionValue{Name: "rise"}, + &ServerOptionValue{Name: "resolve-opts"}, + &ServerOptionValue{Name: "resolve-prefer"}, + &ServerOptionValue{Name: "resolve-net"}, + &ServerOptionValue{Name: "resolvers"}, + &ServerOptionValue{Name: "proxy-v2-options"}, + &ServerOptionValue{Name: "shard"}, + &ServerOptionValue{Name: "sigalgs"}, + &ServerOptionValue{Name: "slowstart"}, + &ServerOptionValue{Name: "sni"}, + &ServerOptionValue{Name: "source"}, + &ServerOptionValue{Name: "usesrc"}, + &ServerOptionValue{Name: "interface"}, + &ServerOptionValue{Name: "ssl-max-ver"}, + &ServerOptionValue{Name: "ssl-min-ver"}, + &ServerOptionValue{Name: "socks4"}, + &ServerOptionValue{Name: "tcp-ut"}, + &ServerOptionValue{Name: "track"}, + &ServerOptionValue{Name: "verify"}, + &ServerOptionValue{Name: "verifyhost"}, + &ServerOptionValue{Name: "weight"}, + &ServerOptionValue{Name: "pool-low-conn"}, + &ServerOptionValue{Name: "ws"}, + &ServerOptionValue{Name: "log-bufsize"}, + &ServerOptionIDValue{Name: "set-proxy-v2-tlv-fmt"}, + } +} + +// Parse ... +func ParseServerOptions(options []string) []ServerOption { + result := []ServerOption{} + currentIndex := 0 + for currentIndex < len(options) { + found := false + for _, parser := range getServerOptions() { + if size, err := parser.Parse(options, currentIndex); err == nil { + result = append(result, parser) + found = true + currentIndex += size + } + } + if !found { + currentIndex++ + } + } + return result +} + +func ServerOptionsString(options []ServerOption) string { + var sb strings.Builder + first := true + for _, parser := range options { + if parser.Valid() { + if !first { + sb.WriteString(" ") + } else { + first = false + } + sb.WriteString(parser.String()) + } + } + return sb.String() +} + +// CreateServerOptionWord creates valid one word value +func CreateServerOptionWord(name string) (ServerOptionWord, ErrParseServerOption) { + b := ServerOptionWord{ + Name: name, + } + _, err := b.Parse([]string{name}, 0) + return b, err +} + +// CreateServerOptionDoubleWord creates valid two word value +func CreateServerOptionDoubleWord(name1 string, name2 string) (ServerOptionDoubleWord, ErrParseServerOption) { + b := ServerOptionDoubleWord{ + Name: name1, + Value: name2, + } + _, err := b.Parse([]string{name1, name2}, 0) + return b, err +} + +// CreateServerOptionValue creates valid option with value +func CreateServerOptionValue(name string, value string) (ServerOptionValue, ErrParseServerOption) { + b := ServerOptionValue{ + Name: name, + Value: value, + } + _, err := b.Parse([]string{name, value}, 0) + return b, err +} diff --git a/config-parser/parser-type.go b/config-parser/parser-type.go new file mode 100644 index 00000000..4f136661 --- /dev/null +++ b/config-parser/parser-type.go @@ -0,0 +1,130 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package parser + +import ( + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" +) + +type ParserInterface interface { //nolint:revive + Init() + Parse(line string, parts []string, comment string) (changeState string, err error) + PreParse(line string, parts []string, preComments []string, comment string) (changeState string, err error) + GetParserName() string + Get(createIfNotExist bool) (common.ParserData, error) + GetPreComments() ([]string, error) + GetOne(index int) (common.ParserData, error) + Delete(index int) error + Insert(data common.ParserData, index int) error + Set(data common.ParserData, index int) error + SetPreComments(preComment []string) + ResultAll() ([]common.ReturnResultLine, []string, error) +} + +type Parsers struct { + Parsers map[string]ParserInterface + ParserSequence []Section + PreComments []string + PostComments []string + DefaultSectionName string +} + +func (p *Parsers) Get(attribute string, createIfNotExist ...bool) (common.ParserData, error) { + createNew := false + if len(createIfNotExist) > 0 && createIfNotExist[0] { + createNew = true + } + if parser, ok := p.Parsers[attribute]; ok { + return parser.Get(createNew) + } + + return nil, errors.ErrParserMissing +} + +func (p *Parsers) GetPreComments(attribute string) ([]string, error) { + if parser, ok := p.Parsers[attribute]; ok { + return parser.GetPreComments() + } + + return nil, errors.ErrParserMissing +} + +func (p *Parsers) GetOne(attribute string, index ...int) (common.ParserData, error) { + setIndex := -1 + if len(index) > 0 && index[0] > -1 { + setIndex = index[0] + } + if parser, ok := p.Parsers[attribute]; ok { + return parser.GetOne(setIndex) + } + + return nil, errors.ErrParserMissing +} + +// HasParser checks if we have a parser for attribute +func (p *Parsers) HasParser(attribute string) bool { + _, hasParser := p.Parsers[attribute] + return hasParser +} + +// Set sets data in parser, if you can have multiple items, index is a must +func (p *Parsers) Set(attribute string, data common.ParserData, index ...int) error { + setIndex := -1 + if len(index) > 0 && index[0] > -1 { + setIndex = index[0] + } + if parser, ok := p.Parsers[attribute]; ok { + return parser.Set(data, setIndex) + } + + return errors.ErrAttributeNotFound +} + +// SetPreComments sets comment lines before parser +func (p *Parsers) SetPreComments(attribute string, preComment []string) error { + if parser, ok := p.Parsers[attribute]; ok { + parser.SetPreComments(preComment) + return nil + } + + return errors.ErrAttributeNotFound +} + +func (p *Parsers) Insert(attribute string, data common.ParserData, index ...int) error { + setIndex := -1 + if len(index) > 0 && index[0] > -1 { + setIndex = index[0] + } + if parser, ok := p.Parsers[attribute]; ok { + return parser.Insert(data, setIndex) + } + + return errors.ErrAttributeNotFound +} + +func (p *Parsers) Delete(attribute string, index ...int) error { + setIndex := -1 + if len(index) > 0 && index[0] > -1 { + setIndex = index[0] + } + if parser, ok := p.Parsers[attribute]; ok { + return parser.Delete(setIndex) + } + + return errors.ErrAttributeNotFound +} diff --git a/config-parser/parser.go b/config-parser/parser.go new file mode 100644 index 00000000..b5b72b8d --- /dev/null +++ b/config-parser/parser.go @@ -0,0 +1,131 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package parser + +import ( + "bytes" + "io" + "os" + "strings" + "sync" + + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/options" +) + +type Section string + +const ( + Comments Section = "#" + Defaults Section = "defaults" + Global Section = "global" + Resolvers Section = "resolvers" + UserList Section = "userlist" + Peers Section = "peers" + Mailers Section = "mailers" + Frontends Section = "frontend" + Backends Section = "backend" + Listen Section = "listen" + Cache Section = "cache" + Program Section = "program" + HTTPErrors Section = "http-errors" + Ring Section = "ring" + LogForward Section = "log-forward" + FCGIApp Section = "fcgi-app" + // spoe sections + SPOEAgent Section = "spoe-agent" + SPOEGroup Section = "spoe-group" + SPOEMessage Section = "spoe-message" +) + +const ( + CommentsSectionName = "data" + GlobalSectionName = "data" +) + +var DefaultSectionName = "" //nolint:gochecknoglobals + +type Parser interface { + LoadData(path string) error + Process(reader io.Reader) error + String() string + Save(filename string) error + StringWithHash() (string, error) + Get(sectionType Section, sectionName string, attribute string, createIfNotExist ...bool) (common.ParserData, error) + GetPreComments(sectionType Section, sectionName string, attribute string) ([]string, error) + GetOne(sectionType Section, sectionName string, attribute string, index ...int) (common.ParserData, error) + SectionsGet(sectionType Section) ([]string, error) + SectionsDelete(sectionType Section, sectionName string) error + SectionsCreate(sectionType Section, sectionName string) error + SectionsDefaultsFromGet(sectionType Section, sectionName string) (string, error) + SectionsDefaultsFromSet(sectionType Section, sectionName, defaultsSection string) error + Set(sectionType Section, sectionName string, attribute string, data common.ParserData, index ...int) error + SetPreComments(sectionType Section, sectionName string, attribute string, preComment []string) error + Delete(sectionType Section, sectionName string, attribute string, index ...int) error + Insert(sectionType Section, sectionName string, attribute string, data common.ParserData, index ...int) error + HasParser(sectionType Section, attribute string) bool + SetLoggerState(active bool) error +} + +type UnlockError struct{} + +func (e UnlockError) Error() string { + return "failed funclock" +} + +// configParser reads and writes configuration on given file +type configParser struct { + Parsers map[Section]map[string]*Parsers + Options options.Parser + lastDefaultsSectionName string + mutex *sync.Mutex +} + +func New(opt ...options.ParserOption) (Parser, error) { + p := &configParser{ + Options: options.Parser{}, + lastDefaultsSectionName: "", + } + var err error + + for _, option := range opt { + err = option.Set(&p.Options) + if err != nil { + return nil, err + } + } + if p.Options.Path != "" { + if p.Options.Log { + p.Options.Logger.Infof("%sreading configuration from file: %s", p.Options.LogPrefix, p.Options.Path) + } + dat, err := os.ReadFile(p.Options.Path) + if err != nil { + return nil, err + } + return p, p.Process(bytes.NewReader(dat)) + } + if p.Options.Reader != nil { + if p.Options.Log { + p.Options.Logger.Infof("%sreading configuration from reader", p.Options.LogPrefix) + } + return p, p.Process(p.Options.Reader) + } + if p.Options.Log { + p.Options.Logger.Warningf("%sno configuration source provided", p.Options.LogPrefix) + } + return p, p.Process(strings.NewReader("")) +} diff --git a/config-parser/parsers/acl.go b/config-parser/parsers/acl.go new file mode 100644 index 00000000..5f90167b --- /dev/null +++ b/config-parser/parsers/acl.go @@ -0,0 +1,64 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package parsers + +import ( + "strings" + + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +type ACL struct { + data []types.ACL + preComments []string // comments that appear before the actual line +} + +func (h *ACL) parse(line string, parts []string, comment string) (*types.ACL, error) { + if len(parts) >= 3 { + data := &types.ACL{ + Name: parts[1], + Criterion: parts[2], + Value: strings.Join(parts[3:], " "), + Comment: comment, + } + return data, nil + } + return nil, &errors.ParseError{Parser: "ACLLines", Line: line} +} + +func (h *ACL) Result() ([]common.ReturnResultLine, error) { + if len(h.data) == 0 { + return nil, errors.ErrFetch + } + result := make([]common.ReturnResultLine, len(h.data)) + for index, req := range h.data { + var sb strings.Builder + sb.WriteString("acl ") + sb.WriteString(req.Name) + sb.WriteString(" ") + sb.WriteString(req.Criterion) + sb.WriteString(" ") + sb.WriteString(req.Value) + result[index] = common.ReturnResultLine{ + Data: sb.String(), + Comment: req.Comment, + } + } + return result, nil +} diff --git a/config-parser/parsers/acl_generated.go b/config-parser/parsers/acl_generated.go new file mode 100644 index 00000000..e462f143 --- /dev/null +++ b/config-parser/parsers/acl_generated.go @@ -0,0 +1,157 @@ +// Code generated by go generate; DO NOT EDIT. +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package parsers + +import ( + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +func (p *ACL) Init() { + p.data = []types.ACL{} + p.preComments = []string{} +} + +func (p *ACL) GetParserName() string { + return "acl" +} + +func (p *ACL) Get(createIfNotExist bool) (common.ParserData, error) { + if len(p.data) == 0 && !createIfNotExist { + return nil, errors.ErrFetch + } + return p.data, nil +} + +func (p *ACL) GetPreComments() ([]string, error) { + return p.preComments, nil +} + +func (p *ACL) SetPreComments(preComments []string) { + p.preComments = preComments +} + +func (p *ACL) GetOne(index int) (common.ParserData, error) { + if index < 0 || index >= len(p.data) { + return nil, errors.ErrFetch + } + return p.data[index], nil +} + +func (p *ACL) Delete(index int) error { + if index < 0 || index >= len(p.data) { + return errors.ErrFetch + } + copy(p.data[index:], p.data[index+1:]) + p.data[len(p.data)-1] = types.ACL{} + p.data = p.data[:len(p.data)-1] + return nil +} + +func (p *ACL) Insert(data common.ParserData, index int) error { + if data == nil { + return errors.ErrInvalidData + } + switch newValue := data.(type) { + case []types.ACL: + p.data = newValue + case *types.ACL: + if index > -1 { + if index > len(p.data) { + return errors.ErrIndexOutOfRange + } + p.data = append(p.data, types.ACL{}) + copy(p.data[index+1:], p.data[index:]) + p.data[index] = *newValue + } else { + p.data = append(p.data, *newValue) + } + case types.ACL: + if index > -1 { + if index > len(p.data) { + return errors.ErrIndexOutOfRange + } + p.data = append(p.data, types.ACL{}) + copy(p.data[index+1:], p.data[index:]) + p.data[index] = newValue + } else { + p.data = append(p.data, newValue) + } + default: + return errors.ErrInvalidData + } + return nil +} + +func (p *ACL) Set(data common.ParserData, index int) error { + if data == nil { + p.Init() + return nil + } + switch newValue := data.(type) { + case []types.ACL: + p.data = newValue + case *types.ACL: + if index > -1 && index < len(p.data) { + p.data[index] = *newValue + } else if index == -1 { + p.data = append(p.data, *newValue) + } else { + return errors.ErrIndexOutOfRange + } + case types.ACL: + if index > -1 && index < len(p.data) { + p.data[index] = newValue + } else if index == -1 { + p.data = append(p.data, newValue) + } else { + return errors.ErrIndexOutOfRange + } + default: + return errors.ErrInvalidData + } + return nil +} + +func (p *ACL) PreParse(line string, parts []string, preComments []string, comment string) (string, error) { + changeState, err := p.Parse(line, parts, comment) + if err == nil && preComments != nil { + p.preComments = append(p.preComments, preComments...) + } + return changeState, err +} + +func (p *ACL) Parse(line string, parts []string, comment string) (string, error) { + if parts[0] == "acl" { + data, err := p.parse(line, parts, comment) + if err != nil { + if _, ok := err.(*errors.ParseError); ok { + return "", err + } + return "", &errors.ParseError{Parser: "ACL", Line: line} + } + p.data = append(p.data, *data) + return "", nil + } + return "", &errors.ParseError{Parser: "ACL", Line: line} +} + +func (p *ACL) ResultAll() ([]common.ReturnResultLine, []string, error) { + res, err := p.Result() + return res, p.preComments, err +} diff --git a/config-parser/parsers/actions/check-connect.go b/config-parser/parsers/actions/check-connect.go new file mode 100644 index 00000000..2527206c --- /dev/null +++ b/config-parser/parsers/actions/check-connect.go @@ -0,0 +1,120 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package actions + +import ( + "fmt" + "strings" + + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +// tcp/http-check connect +// +// [default] [port ] [addr ] [send-proxy] +// [via-socks4] [ssl] [sni ] [alpn ] [linger] +// [proto ] [comment ] +type CheckConnect struct { + Port string + Addr string + SNI string + ALPN string + Proto string + CheckComment string + Comment string + Default bool + SendProxy bool + ViaSOCKS4 bool + SSL bool + Linger bool +} + +func (c *CheckConnect) Parse(parts []string, parserType types.ParserType, comment string) error { + if comment != "" { + c.Comment = comment + } + + // Note: "tcp/http-check connect" with no further params is allowed by HAProxy + if len(parts) < 2 { + return fmt.Errorf("not enough params") + } + + for i := 2; i < len(parts); i++ { + el := parts[i] + switch el { + case "default": + c.Default = true + case "port": + CheckParsePair(parts, &i, &c.Port) + case "addr": + CheckParsePair(parts, &i, &c.Addr) + case "send-proxy": + c.SendProxy = true + case "via-socks4": + c.ViaSOCKS4 = true + case "ssl": + c.SSL = true + case "sni": + CheckParsePair(parts, &i, &c.SNI) + case "alpn": + CheckParsePair(parts, &i, &c.ALPN) + case "linger": + c.Linger = true + case "proto": + CheckParsePair(parts, &i, &c.Proto) + case "comment": + CheckParsePair(parts, &i, &c.CheckComment) + } + } + + return nil +} + +func (c *CheckConnect) String() string { + sb := &strings.Builder{} + + sb.WriteString("connect") + + if c.Default { + CheckWritePair(sb, "", "default") + } + CheckWritePair(sb, "port", c.Port) + CheckWritePair(sb, "addr", c.Addr) + if c.SendProxy { + CheckWritePair(sb, "", "send-proxy") + } + if c.ViaSOCKS4 { + CheckWritePair(sb, "", "via-socks4") + } + if c.SSL { + CheckWritePair(sb, "", "ssl") + } + CheckWritePair(sb, "sni", c.SNI) + CheckWritePair(sb, "alpn", c.ALPN) + + if c.Linger { + CheckWritePair(sb, "", "linger") + } + CheckWritePair(sb, "proto", c.Proto) + CheckWritePair(sb, "comment", c.CheckComment) + + return sb.String() +} + +func (c *CheckConnect) GetComment() string { + return c.Comment +} diff --git a/config-parser/parsers/actions/check-expect.go b/config-parser/parsers/actions/check-expect.go new file mode 100644 index 00000000..ac79ef03 --- /dev/null +++ b/config-parser/parsers/actions/check-expect.go @@ -0,0 +1,145 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package actions + +import ( + "fmt" + "strconv" + "strings" + + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +// http-check/tcp-check expect +// +// [min-recv ] [comment ] +// [ok-status ] [error-status ] [tout-status ] +// [on-success ] [on-error ] [status-code ] +// [!] +type CheckExpect struct { + MinRecv *int64 + CheckComment string + OKStatus string + ErrorStatus string + TimeoutStatus string + OnSuccess string + OnError string + StatusCode string + ExclamationMark bool + Match string + Pattern string + Comment string +} + +func (c *CheckExpect) Parse(parts []string, parserType types.ParserType, comment string) error { + if comment != "" { + c.Comment = comment + } + + if len(parts) < 3 { + return fmt.Errorf("not enough params") + } + + var i int +LoopExpect: + for i = 2; i < len(parts); i++ { + el := parts[i] + switch el { + case "min-recv": + if (i + 1) < len(parts) { + // a *int64 is used as opposed to just int64 since 0 has a special meaning for min-recv + minRecv, err := strconv.ParseInt(parts[i+1], 10, 64) + if err != nil { + return err + } + c.MinRecv = &minRecv + i++ + } + case "comment": + CheckParsePair(parts, &i, &c.CheckComment) + case "ok-status": + CheckParsePair(parts, &i, &c.OKStatus) + case "error-status": + CheckParsePair(parts, &i, &c.ErrorStatus) + case "tout-status": + CheckParsePair(parts, &i, &c.TimeoutStatus) + case "on-success": + CheckParsePair(parts, &i, &c.OnSuccess) + case "on-error": + CheckParsePair(parts, &i, &c.OnError) + case "status-code": + CheckParsePair(parts, &i, &c.StatusCode) + case "!": + c.ExclamationMark = true + default: + break LoopExpect + } + } + + // if we broke out of the loop, whatever is leftover should be + // ` `. Prevent panics with bounds checks for safety. + if i >= len(parts) { + if parserType == types.HTTP { + return &errors.ParseError{Parser: "HttpCheck", Message: "http-check expect: match not provided"} + } + return &errors.ParseError{Parser: "TcpCheck", Message: "tcp-check expect: match not provided"} + } + c.Match = parts[i] + + if i+1 >= len(parts) { + if parserType == types.HTTP { + return &errors.ParseError{Parser: "HttpCheck", Message: "http-check expect: pattern not provided"} + } + return &errors.ParseError{Parser: "TcpCheck", Message: "tcp-check expect: pattern not provided"} + } + // Since pattern is always the last option provided, we can safely join + // the remainder as part of the pattern. + pattern := strings.Join(parts[i+1:], " ") + c.Pattern = pattern + + return nil +} + +func (c *CheckExpect) String() string { + sb := &strings.Builder{} + + sb.WriteString("expect") + + if c.MinRecv != nil { + CheckWritePair(sb, "min-recv", strconv.Itoa(int(*c.MinRecv))) + } + CheckWritePair(sb, "comment", c.CheckComment) + CheckWritePair(sb, "ok-status", c.OKStatus) + CheckWritePair(sb, "error-status", c.ErrorStatus) + CheckWritePair(sb, "tout-status", c.TimeoutStatus) + CheckWritePair(sb, "on-success", c.OnSuccess) + CheckWritePair(sb, "on-error", c.OnError) + CheckWritePair(sb, "status-code", c.StatusCode) + + if c.ExclamationMark { + CheckWritePair(sb, "", "!") + } + CheckWritePair(sb, "", c.Match) + CheckWritePair(sb, "", c.Pattern) + + return sb.String() +} + +func (c *CheckExpect) GetComment() string { + return c.Comment +} diff --git a/config-parser/parsers/actions/check-set-var-fmt.go b/config-parser/parsers/actions/check-set-var-fmt.go new file mode 100644 index 00000000..a22da035 --- /dev/null +++ b/config-parser/parsers/actions/check-set-var-fmt.go @@ -0,0 +1,78 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +//nolint:dupl +package actions + +import ( + "fmt" + "strings" + + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +type SetVarFmtCheck struct { + VarScope string + VarName string + Format common.Expression + Comment string +} + +func (f *SetVarFmtCheck) Parse(parts []string, parserType types.ParserType, comment string) error { + if comment != "" { + f.Comment = comment + } + if len(parts) < 3 { + return fmt.Errorf("not enough params") + } + var data string + var command []string + + data = parts[1] + command = parts[2:] + + data = strings.TrimPrefix(data, "set-var-fmt(") + data = strings.TrimRight(data, ")") + d := strings.SplitN(data, ".", 2) + f.VarScope = d[0] + f.VarName = d[1] + command, condition := common.SplitRequest(command) + if len(command) > 0 { + format := common.Expression{} + err := format.Parse(command) + if err != nil { + return fmt.Errorf("not enough params") + } + f.Format = format + } else { + return fmt.Errorf("not enough params") + } + if len(condition) > 1 { + return errors.ErrInvalidData + } + + return nil +} + +func (f *SetVarFmtCheck) String() string { + return fmt.Sprintf("set-var-fmt(%s.%s) %s", f.VarScope, f.VarName, f.Format.String()) +} + +func (f *SetVarFmtCheck) GetComment() string { + return f.Comment +} diff --git a/config-parser/parsers/actions/do-resolve.go b/config-parser/parsers/actions/do-resolve.go new file mode 100644 index 00000000..1a696958 --- /dev/null +++ b/config-parser/parsers/actions/do-resolve.go @@ -0,0 +1,101 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package actions + +import ( + "fmt" + "strings" + + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +type DoResolve struct { + Var string + Resolvers string + Protocol string + Expr common.Expression + Cond string + CondTest string + Comment string +} + +func (f *DoResolve) Parse(parts []string, parserType types.ParserType, comment string) error { + if comment != "" { + f.Comment = comment + } + if len(parts) < 3 { + return fmt.Errorf("not enough params") + } + var data string + var command []string + switch parserType { + case types.HTTP: + data = parts[1] + command = parts[2:] + case types.TCP: + data = parts[2] + command = parts[3:] + } + data = strings.TrimPrefix(data, "do-resolve(") + data = strings.TrimRight(data, ")") + d := strings.SplitN(data, ",", 3) + + if len(d) < 2 { + return fmt.Errorf("not enough params") + } + + f.Var = d[0] + f.Resolvers = d[1] + if len(d) == 3 { + f.Protocol = d[2] + } + + command, condition := common.SplitRequest(command) + if len(command) > 0 { + expr := common.Expression{} + err := expr.Parse(command) + if err != nil { + return fmt.Errorf("not enough params") + } + f.Expr = expr + } + + if len(condition) > 1 { + f.Cond = condition[0] + f.CondTest = strings.Join(condition[1:], " ") + } + return nil +} + +func (f *DoResolve) String() string { + var stmt string + if len(f.Protocol) > 0 { + stmt = fmt.Sprintf("%s,%s,%s", f.Var, f.Resolvers, f.Protocol) + } else { + stmt = fmt.Sprintf("%s,%s", f.Var, f.Resolvers) + } + + if f.Cond == "" { + return fmt.Sprintf("do-resolve(%s) %s", stmt, f.Expr.String()) + } + return fmt.Sprintf("do-resolve(%s) %s %s %s", stmt, f.Expr.String(), f.Cond, f.CondTest) +} + +func (f *DoResolve) GetComment() string { + return f.Comment +} diff --git a/config-parser/parsers/actions/lua.go b/config-parser/parsers/actions/lua.go new file mode 100644 index 00000000..92277eda --- /dev/null +++ b/config-parser/parsers/actions/lua.go @@ -0,0 +1,89 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package actions + +import ( + "fmt" + "strings" + + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +type Lua struct { + Action string + Params string + Cond string + CondTest string + Comment string +} + +func (f *Lua) Parse(parts []string, parserType types.ParserType, comment string) error { + if comment != "" { + f.Comment = comment + } + if len(parts) < 2 { + return fmt.Errorf("not enough params") + } + var data string + var command []string + switch parserType { + case types.HTTP: + data = parts[1] + command = parts[2:] + case types.TCP: + data = parts[2] + command = parts[3:] + } + + f.Action = strings.TrimPrefix(data, "lua.") + if f.Action == "" { + return errors.ErrInvalidData + } + if len(parts) > 2 { + var condition []string + command, condition = common.SplitRequest(command) + f.Params = strings.Join(command, " ") + if len(condition) > 1 { + f.Cond = condition[0] + f.CondTest = strings.Join(condition[1:], " ") + } + } + return nil +} + +func (f *Lua) String() string { + var result strings.Builder + result.WriteString("lua.") + result.WriteString(f.Action) + if f.Params != "" { + result.WriteString(" ") + result.WriteString(f.Params) + } + if f.Cond != "" { + result.WriteString(" ") + result.WriteString(f.Cond) + result.WriteString(" ") + result.WriteString(f.CondTest) + } + return result.String() +} + +func (f *Lua) GetComment() string { + return f.Comment +} diff --git a/config-parser/parsers/actions/misc.go b/config-parser/parsers/actions/misc.go new file mode 100644 index 00000000..5adac6ef --- /dev/null +++ b/config-parser/parsers/actions/misc.go @@ -0,0 +1,36 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package actions + +import "io" + +func CheckParsePair(parts []string, i *int, str *string) { + if (*i + 1) < len(parts) { + *str = parts[*i+1] + *i++ + } +} + +func CheckWritePair(sb io.StringWriter, key string, value string) { + if value != "" { + _, _ = sb.WriteString(" ") + if key != "" { + _, _ = sb.WriteString(key) + _, _ = sb.WriteString(" ") + } + _, _ = sb.WriteString(value) + } +} diff --git a/config-parser/parsers/actions/reject.go b/config-parser/parsers/actions/reject.go new file mode 100644 index 00000000..4aa2f646 --- /dev/null +++ b/config-parser/parsers/actions/reject.go @@ -0,0 +1,72 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package actions + +import ( + "fmt" + "strings" + + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +type Reject struct { + Cond string + CondTest string + Comment string +} + +func (f *Reject) Parse(parts []string, parserType types.ParserType, comment string) error { + if comment != "" { + f.Comment = comment + } + var command []string + var minLen, requiredLen int + switch parserType { + case types.HTTP: + command = parts[1:] + minLen = 2 + requiredLen = 4 + case types.TCP: + command = parts[2:] + minLen = 3 + requiredLen = 5 + } + if len(parts) == minLen { + return nil + } + if len(parts) < requiredLen { + return fmt.Errorf("not enough params") + } + _, condition := common.SplitRequest(command) + if len(condition) > 1 { + f.Cond = condition[0] + f.CondTest = strings.Join(condition[1:], " ") + } + return nil +} + +func (f *Reject) String() string { + if f.Cond != "" { + return fmt.Sprintf("reject %s %s", f.Cond, f.CondTest) + } + return "reject" +} + +func (f *Reject) GetComment() string { + return f.Comment +} diff --git a/config-parser/parsers/actions/sc-inc-gpc0.go b/config-parser/parsers/actions/sc-inc-gpc0.go new file mode 100644 index 00000000..7f21393f --- /dev/null +++ b/config-parser/parsers/actions/sc-inc-gpc0.go @@ -0,0 +1,86 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +//nolint:dupl +package actions + +import ( + "fmt" + "strings" + + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +type ScIncGpc0 struct { + ID string + Cond string + CondTest string + Comment string +} + +func (f *ScIncGpc0) Parse(parts []string, parserType types.ParserType, comment string) error { + if comment != "" { + f.Comment = comment + } + var data string + var command []string + var minLen, requiredLen int + switch parserType { + case types.HTTP: + data = parts[1] + command = parts[2:] + minLen = 2 + requiredLen = 4 + case types.TCP: + data = parts[2] + command = parts[3:] + minLen = 3 + requiredLen = 5 + } + f.ID = strings.TrimPrefix(data, "sc-inc-gpc0(") + f.ID = strings.TrimRight(f.ID, ")") + if len(parts) == minLen { + return nil + } + if len(parts) < requiredLen { + return fmt.Errorf("not enough params") + } + _, condition := common.SplitRequest(command) + if len(condition) > 1 { + f.Cond = condition[0] + f.CondTest = strings.Join(condition[1:], " ") + } + return nil +} + +func (f *ScIncGpc0) String() string { + var result strings.Builder + result.WriteString("sc-inc-gpc0(") + result.WriteString(f.ID) + result.WriteString(")") + if f.Cond != "" { + result.WriteString(" ") + result.WriteString(f.Cond) + result.WriteString(" ") + result.WriteString(f.CondTest) + } + return result.String() +} + +func (f *ScIncGpc0) GetComment() string { + return f.Comment +} diff --git a/config-parser/parsers/actions/sc-inc-gpc1.go b/config-parser/parsers/actions/sc-inc-gpc1.go new file mode 100644 index 00000000..96bfe0b0 --- /dev/null +++ b/config-parser/parsers/actions/sc-inc-gpc1.go @@ -0,0 +1,86 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +//nolint:dupl +package actions + +import ( + "fmt" + "strings" + + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +type ScIncGpc1 struct { + ID string + Cond string + CondTest string + Comment string +} + +func (f *ScIncGpc1) Parse(parts []string, parserType types.ParserType, comment string) error { + if comment != "" { + f.Comment = comment + } + var data string + var command []string + var minLen, requiredLen int + switch parserType { + case types.HTTP: + data = parts[1] + command = parts[2:] + minLen = 2 + requiredLen = 4 + case types.TCP: + data = parts[2] + command = parts[3:] + minLen = 3 + requiredLen = 5 + } + f.ID = strings.TrimPrefix(data, "sc-inc-gpc1(") + f.ID = strings.TrimRight(f.ID, ")") + if len(parts) == minLen { + return nil + } + if len(parts) < requiredLen { + return fmt.Errorf("not enough params") + } + _, condition := common.SplitRequest(command) + if len(condition) > 1 { + f.Cond = condition[0] + f.CondTest = strings.Join(condition[1:], " ") + } + return nil +} + +func (f *ScIncGpc1) String() string { + var result strings.Builder + result.WriteString("sc-inc-gpc1(") + result.WriteString(f.ID) + result.WriteString(")") + if f.Cond != "" { + result.WriteString(" ") + result.WriteString(f.Cond) + result.WriteString(" ") + result.WriteString(f.CondTest) + } + return result.String() +} + +func (f *ScIncGpc1) GetComment() string { + return f.Comment +} diff --git a/config-parser/parsers/actions/sc-set-gpt.go b/config-parser/parsers/actions/sc-set-gpt.go new file mode 100644 index 00000000..a51431a4 --- /dev/null +++ b/config-parser/parsers/actions/sc-set-gpt.go @@ -0,0 +1,118 @@ +/* +Copyright 2024 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package actions + +import ( + "fmt" + "strconv" + "strings" + + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +type ScSetGpt struct { + ScID string + Idx int64 + Int *int64 + Expr common.Expression + Cond string + CondTest string + Comment string +} + +func (f *ScSetGpt) Parse(parts []string, parserType types.ParserType, comment string) error { + if comment != "" { + f.Comment = comment + } + if len(parts) < 3 { + return fmt.Errorf("not enough params") + } + var data string + var command []string + switch parserType { + case types.HTTP: + data = parts[1] + command = parts[2:] + case types.TCP: + data = parts[2] + command = parts[3:] + } + + // sc-get-gpt(sc-id,idx) + start := len("sc-set-gpt(") + end := len(data) - 1 // ignore ")" + idIdx := strings.Split(data[start:end], ",") + if len(idIdx) != 2 { + return fmt.Errorf("missing sc-id and/or idx") + } + var err error + f.ScID = idIdx[0] + f.Idx, err = strconv.ParseInt(idIdx[1], 10, 64) + if err != nil { + return fmt.Errorf("failed to parse idx: %w", err) + } + + // { | } [ { if | unless } ] + command, condition := common.SplitRequest(command) + if len(command) < 1 { + return errors.ErrInvalidData + } + i, err := strconv.ParseInt(command[0], 10, 64) + if err == nil { + f.Int = &i + } else { + expr := common.Expression{} + err := expr.Parse(command) + if err != nil { + return fmt.Errorf("not enough params") + } + f.Expr = expr + } + if len(condition) > 1 { + f.Cond = condition[0] + f.CondTest = strings.Join(condition[1:], " ") + } + return nil +} + +func (f *ScSetGpt) String() string { + var result strings.Builder + result.Grow(64) + result.WriteString("sc-set-gpt(") + result.WriteString(f.ScID) + result.WriteByte(',') + result.WriteString(strconv.FormatInt(f.Idx, 10)) + result.WriteString(") ") + if f.Int != nil { + result.WriteString(strconv.FormatInt(*f.Int, 10)) + } else { + result.WriteString(f.Expr.String()) + } + if f.Cond != "" { + result.WriteString(" ") + result.WriteString(f.Cond) + result.WriteString(" ") + result.WriteString(f.CondTest) + } + return result.String() +} + +func (f *ScSetGpt) GetComment() string { + return f.Comment +} diff --git a/config-parser/parsers/actions/sc-set-gpt0.go b/config-parser/parsers/actions/sc-set-gpt0.go new file mode 100644 index 00000000..328fc3df --- /dev/null +++ b/config-parser/parsers/actions/sc-set-gpt0.go @@ -0,0 +1,100 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package actions + +import ( + "fmt" + "strconv" + "strings" + + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +type ScSetGpt0 struct { + ID string + Int *int64 + Expr common.Expression + Cond string + CondTest string + Comment string +} + +func (f *ScSetGpt0) Parse(parts []string, parserType types.ParserType, comment string) error { + if comment != "" { + f.Comment = comment + } + if len(parts) < 3 { + return fmt.Errorf("not enough params") + } + var data string + var command []string + switch parserType { + case types.HTTP: + data = parts[1] + command = parts[2:] + case types.TCP: + data = parts[2] + command = parts[3:] + } + f.ID = strings.TrimPrefix(data, "sc-set-gpt0(") + f.ID = strings.TrimRight(f.ID, ")") + command, condition := common.SplitRequest(command) + if len(command) < 1 { + return errors.ErrInvalidData + } + i, err := strconv.ParseInt(command[0], 10, 64) + if err == nil { + f.Int = &i + } else { + expr := common.Expression{} + err := expr.Parse(command) + if err != nil { + return fmt.Errorf("not enough params") + } + f.Expr = expr + } + if len(condition) > 1 { + f.Cond = condition[0] + f.CondTest = strings.Join(condition[1:], " ") + } + return nil +} + +func (f *ScSetGpt0) String() string { + var result strings.Builder + result.WriteString("sc-set-gpt0(") + result.WriteString(f.ID) + result.WriteString(") ") + if f.Int != nil { + result.WriteString(strconv.FormatInt(*f.Int, 10)) + } else { + result.WriteString(f.Expr.String()) + } + if f.Cond != "" { + result.WriteString(" ") + result.WriteString(f.Cond) + result.WriteString(" ") + result.WriteString(f.CondTest) + } + return result.String() +} + +func (f *ScSetGpt0) GetComment() string { + return f.Comment +} diff --git a/config-parser/parsers/actions/sc_add_gpc.go b/config-parser/parsers/actions/sc_add_gpc.go new file mode 100644 index 00000000..9131caad --- /dev/null +++ b/config-parser/parsers/actions/sc_add_gpc.go @@ -0,0 +1,109 @@ +/* +Copyright 2023 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package actions + +import ( + "fmt" + "strconv" + "strings" + + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +type ScAddGpc struct { + Idx string + ID string + Int *int64 + Expr common.Expression + Cond string + CondTest string + Comment string +} + +func (f *ScAddGpc) Parse(parts []string, parserType types.ParserType, comment string) error { + if comment != "" { + f.Comment = comment + } + var data string + var command []string + var minLen int + switch parserType { + case types.HTTP: + data = parts[1] + command = parts[2:] + minLen = 3 + case types.TCP: + data = parts[2] + command = parts[3:] + minLen = 4 + } + idIdx := strings.TrimPrefix(data, "sc-add-gpc(") + idIdx = strings.TrimRight(idIdx, ")") + idIdxValues := strings.SplitN(idIdx, ",", 2) + f.Idx, f.ID = idIdxValues[0], idIdxValues[1] + if len(parts) < minLen { + return fmt.Errorf("not enough params") + } + command, condition := common.SplitRequest(command) + if len(command) < 1 { + return errors.ErrInvalidData + } + i, err := strconv.ParseInt(command[0], 10, 64) + if err == nil { + f.Int = &i + } else { + expr := common.Expression{} + err := expr.Parse(command) + if err != nil { + return fmt.Errorf("not enough params") + } + f.Expr = expr + } + if len(condition) > 1 { + f.Cond = condition[0] + f.CondTest = strings.Join(condition[1:], " ") + } + return nil +} + +func (f *ScAddGpc) String() string { + var result strings.Builder + result.WriteString("sc-add-gpc(") + result.WriteString(f.Idx) + result.WriteString(",") + result.WriteString(f.ID) + result.WriteString(")") + result.WriteString(" ") + if f.Int != nil { + result.WriteString(strconv.FormatInt(*f.Int, 10)) + } else { + result.WriteString(f.Expr.String()) + } + if f.Cond != "" { + result.WriteString(" ") + result.WriteString(f.Cond) + result.WriteString(" ") + result.WriteString(f.CondTest) + } + return result.String() +} + +func (f *ScAddGpc) GetComment() string { + return f.Comment +} diff --git a/config-parser/parsers/actions/sc_inc_gpc.go b/config-parser/parsers/actions/sc_inc_gpc.go new file mode 100644 index 00000000..00448115 --- /dev/null +++ b/config-parser/parsers/actions/sc_inc_gpc.go @@ -0,0 +1,90 @@ +/* +Copyright 2023 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package actions + +import ( + "fmt" + "strings" + + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +type ScIncGpc struct { + Idx string + ID string + Cond string + CondTest string + Comment string +} + +func (f *ScIncGpc) Parse(parts []string, parserType types.ParserType, comment string) error { + if comment != "" { + f.Comment = comment + } + var data string + var command []string + var minLen, requiredLen int + switch parserType { + case types.HTTP: + data = parts[1] + command = parts[2:] + minLen = 2 + requiredLen = 4 + case types.TCP: + data = parts[2] + command = parts[3:] + minLen = 3 + requiredLen = 5 + } + idIdx := strings.TrimPrefix(data, "sc-inc-gpc(") + idIdx = strings.TrimRight(idIdx, ")") + idIdxValues := strings.SplitN(idIdx, ",", 2) + f.Idx, f.ID = idIdxValues[0], idIdxValues[1] + if len(parts) == minLen { + return nil + } + if len(parts) < requiredLen { + return fmt.Errorf("not enough params") + } + _, condition := common.SplitRequest(command) + if len(condition) > 1 { + f.Cond = condition[0] + f.CondTest = strings.Join(condition[1:], " ") + } + return nil +} + +func (f *ScIncGpc) String() string { + var result strings.Builder + result.WriteString("sc-inc-gpc(") + result.WriteString(f.Idx) + result.WriteString(",") + result.WriteString(f.ID) + result.WriteString(")") + if f.Cond != "" { + result.WriteString(" ") + result.WriteString(f.Cond) + result.WriteString(" ") + result.WriteString(f.CondTest) + } + return result.String() +} + +func (f *ScIncGpc) GetComment() string { + return f.Comment +} diff --git a/config-parser/parsers/actions/send-spoe-group.go b/config-parser/parsers/actions/send-spoe-group.go new file mode 100644 index 00000000..ab298e40 --- /dev/null +++ b/config-parser/parsers/actions/send-spoe-group.go @@ -0,0 +1,73 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package actions + +import ( + "fmt" + "strings" + + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +type SendSpoeGroup struct { + Engine string + Group string + Cond string + CondTest string + Comment string +} + +func (f *SendSpoeGroup) Parse(parts []string, parserType types.ParserType, comment string) error { + if comment != "" { + f.Comment = comment + } + if len(parts) < 4 { + return fmt.Errorf("not enough params") + } + var command []string + switch parserType { + case types.HTTP: + command = parts[2:] + case types.TCP: + command = parts[3:] + } + command, condition := common.SplitRequest(command) + if len(command) < 2 { + return errors.ErrInvalidData + } + f.Engine = command[0] + f.Group = command[1] + if len(condition) > 1 { + f.Cond = condition[0] + f.CondTest = strings.Join(condition[1:], " ") + } + return nil +} + +func (f *SendSpoeGroup) String() string { + condition := "" + if f.Cond != "" { + condition = fmt.Sprintf(" %s %s", f.Cond, f.CondTest) + } + return fmt.Sprintf("send-spoe-group %s %s%s", f.Engine, f.Group, condition) +} + +func (f *SendSpoeGroup) GetComment() string { + return f.Comment +} diff --git a/config-parser/parsers/actions/set-bandwidth-limit.go b/config-parser/parsers/actions/set-bandwidth-limit.go new file mode 100644 index 00000000..3003a198 --- /dev/null +++ b/config-parser/parsers/actions/set-bandwidth-limit.go @@ -0,0 +1,120 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package actions + +import ( + "fmt" + "strings" + + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +type SetBandwidthLimit struct { + Limit common.Expression + Period common.Expression + Name string + Cond string + CondTest string + Comment string +} + +func (f *SetBandwidthLimit) Parse(parts []string, parserType types.ParserType, comment string) error { + if comment != "" { + f.Comment = comment + } + + var command []string + switch parserType { + case types.HTTP: + if len(parts) < 3 { + return fmt.Errorf("not enough params") + } + command = parts[2:] + case types.TCP: + if len(parts) < 4 { + return fmt.Errorf("not enough params") + } + command = parts[3:] + } + command, condition := common.SplitRequest(command) + f.Name = command[0] + + for i := 1; i < len(command); i++ { + var expr []string + if len(command) < i+2 { + return fmt.Errorf("not enough params") + } + el := command[i] + switch el { + case "limit": + expr, i = f.parseExpr(command, i+1, "period") + if len(expr) == 0 { + return fmt.Errorf("not enough params") + } + f.Limit.Expr = expr + case "period": + expr, i = f.parseExpr(command, i+1, "limit") + if len(expr) == 0 { + return fmt.Errorf("not enough params") + } + f.Period.Expr = expr + default: + return fmt.Errorf("invalid param %s", el) + } + } + + if len(condition) > 1 { + f.Cond = condition[0] + f.CondTest = strings.Join(condition[1:], " ") + } + return nil +} + +func (f *SetBandwidthLimit) parseExpr(parts []string, start int, end string) ([]string, int) { + for i := start; i < len(parts); i++ { + if parts[i] == end { + return parts[start:i], i - 1 + } + } + return parts[start:], len(parts) - 1 +} + +func (f *SetBandwidthLimit) String() string { + var result strings.Builder + result.WriteString("set-bandwidth-limit ") + result.WriteString(f.Name) + if len(f.Limit.Expr) != 0 { + result.WriteString(" limit ") + result.WriteString(f.Limit.String()) + } + if len(f.Period.Expr) != 0 { + result.WriteString(" period ") + result.WriteString(f.Period.String()) + } + if f.Cond != "" { + result.WriteString(" ") + result.WriteString(f.Cond) + result.WriteString(" ") + result.WriteString(f.CondTest) + } + return result.String() +} + +func (f *SetBandwidthLimit) GetComment() string { + return f.Comment +} diff --git a/config-parser/parsers/actions/set-dst-port.go b/config-parser/parsers/actions/set-dst-port.go new file mode 100644 index 00000000..977214db --- /dev/null +++ b/config-parser/parsers/actions/set-dst-port.go @@ -0,0 +1,74 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package actions + +import ( + "fmt" + "strings" + + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +type SetDstPort struct { + Expr common.Expression + Cond string + CondTest string + Comment string +} + +func (f *SetDstPort) Parse(parts []string, parserType types.ParserType, comment string) error { + if comment != "" { + f.Comment = comment + } + if len(parts) < 3 { + return fmt.Errorf("not enough params") + } + var command []string + switch parserType { + case types.HTTP: + command = parts[2:] + case types.TCP: + command = parts[3:] + } + command, condition := common.SplitRequest(command) + + if len(command) > 0 { + expr := common.Expression{} + err := expr.Parse(command) + if err != nil { + return fmt.Errorf("not enough params") + } + f.Expr = expr + } + if len(condition) > 1 { + f.Cond = condition[0] + f.CondTest = strings.Join(condition[1:], " ") + } + return nil +} + +func (f *SetDstPort) String() string { + if f.Cond == "" { + return fmt.Sprintf("set-dst-port %s", f.Expr.String()) + } + return fmt.Sprintf("set-dst-port %s %s %s", f.Expr.String(), f.Cond, f.CondTest) +} + +func (f *SetDstPort) GetComment() string { + return f.Comment +} diff --git a/config-parser/parsers/actions/set-dst.go b/config-parser/parsers/actions/set-dst.go new file mode 100644 index 00000000..82912881 --- /dev/null +++ b/config-parser/parsers/actions/set-dst.go @@ -0,0 +1,75 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package actions + +import ( + "fmt" + "strings" + + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +type SetDst struct { + Expr common.Expression + Cond string + CondTest string + Comment string +} + +func (f *SetDst) Parse(parts []string, parserType types.ParserType, comment string) error { + if comment != "" { + f.Comment = comment + } + if len(parts) < 3 { + return fmt.Errorf("not enough params") + } + var command []string + switch parserType { + case types.HTTP: + command = parts[2:] + case types.TCP: + command = parts[3:] + } + command, condition := common.SplitRequest(command) + + if len(command) == 0 { + return fmt.Errorf("not enough params") + } + expr := common.Expression{} + + if err := expr.Parse(command); err != nil { + return fmt.Errorf("not enough params") + } + f.Expr = expr + if len(condition) > 1 { + f.Cond = condition[0] + f.CondTest = strings.Join(condition[1:], " ") + } + return nil +} + +func (f *SetDst) String() string { + if f.Cond == "" { + return fmt.Sprintf("set-dst %s", f.Expr.String()) + } + return fmt.Sprintf("set-dst %s %s %s", f.Expr.String(), f.Cond, f.CondTest) +} + +func (f *SetDst) GetComment() string { + return f.Comment +} diff --git a/config-parser/parsers/actions/set-log-level.go b/config-parser/parsers/actions/set-log-level.go new file mode 100644 index 00000000..8d14633d --- /dev/null +++ b/config-parser/parsers/actions/set-log-level.go @@ -0,0 +1,74 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package actions + +import ( + "fmt" + "strings" + + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +type SetLogLevel struct { + Level string + Cond string + CondTest string + Comment string +} + +func (f *SetLogLevel) Parse(parts []string, parserType types.ParserType, comment string) error { + if comment != "" { + f.Comment = comment + } + + var command []string + switch parserType { + case types.HTTP: + command = parts[2:] + case types.TCP: + command = parts[3:] + } + + if len(command) >= 1 { + var condition []string + command, condition = common.SplitRequest(command) + if len(command) == 0 { + return errors.ErrInvalidData + } + f.Level = command[0] + if len(condition) > 1 { + f.Cond = condition[0] + f.CondTest = strings.Join(condition[1:], " ") + } + return nil + } + return fmt.Errorf("not enough params") +} + +func (f *SetLogLevel) String() string { + condition := "" + if f.Cond != "" { + condition = fmt.Sprintf(" %s %s", f.Cond, f.CondTest) + } + return fmt.Sprintf("set-log-level %s%s", f.Level, condition) +} + +func (f *SetLogLevel) GetComment() string { + return f.Comment +} diff --git a/config-parser/parsers/actions/set-mark.go b/config-parser/parsers/actions/set-mark.go new file mode 100644 index 00000000..da49fbbe --- /dev/null +++ b/config-parser/parsers/actions/set-mark.go @@ -0,0 +1,80 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +//nolint:dupl +package actions + +import ( + "fmt" + "strings" + + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +type SetMark struct { + Value string + Cond string + CondTest string + Comment string +} + +func (f *SetMark) Parse(parts []string, parserType types.ParserType, comment string) error { + if comment != "" { + f.Comment = comment + } + + var command []string + switch parserType { + case types.HTTP: + command = parts[2:] + case types.TCP: + command = parts[3:] + } + + if len(command) >= 1 { + var condition []string + command, condition = common.SplitRequest(command) + if len(command) == 0 { + return errors.ErrInvalidData + } + f.Value = command[0] + if len(condition) > 1 { + f.Cond = condition[0] + f.CondTest = strings.Join(condition[1:], " ") + } + return nil + } + return fmt.Errorf("not enough params") +} + +func (f *SetMark) String() string { + var result strings.Builder + result.WriteString("set-mark ") + result.WriteString(f.Value) + if f.Cond != "" { + result.WriteString(" ") + result.WriteString(f.Cond) + result.WriteString(" ") + result.WriteString(f.CondTest) + } + return result.String() +} + +func (f *SetMark) GetComment() string { + return f.Comment +} diff --git a/config-parser/parsers/actions/set-nice.go b/config-parser/parsers/actions/set-nice.go new file mode 100644 index 00000000..1f206736 --- /dev/null +++ b/config-parser/parsers/actions/set-nice.go @@ -0,0 +1,80 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +//nolint:dupl +package actions + +import ( + "fmt" + "strings" + + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +type SetNice struct { + Value string + Cond string + CondTest string + Comment string +} + +func (f *SetNice) Parse(parts []string, parserType types.ParserType, comment string) error { + if comment != "" { + f.Comment = comment + } + + var command []string + switch parserType { + case types.HTTP: + command = parts[2:] + case types.TCP: + command = parts[3:] + } + + if len(parts) >= 1 { + var condition []string + command, condition = common.SplitRequest(command) + if len(command) == 0 { + return errors.ErrInvalidData + } + f.Value = command[0] + if len(condition) > 1 { + f.Cond = condition[0] + f.CondTest = strings.Join(condition[1:], " ") + } + return nil + } + return fmt.Errorf("not enough params") +} + +func (f *SetNice) String() string { + var result strings.Builder + result.WriteString("set-nice ") + result.WriteString(f.Value) + if f.Cond != "" { + result.WriteString(" ") + result.WriteString(f.Cond) + result.WriteString(" ") + result.WriteString(f.CondTest) + } + return result.String() +} + +func (f *SetNice) GetComment() string { + return f.Comment +} diff --git a/config-parser/parsers/actions/set-priority-class.go b/config-parser/parsers/actions/set-priority-class.go new file mode 100644 index 00000000..42fdfd58 --- /dev/null +++ b/config-parser/parsers/actions/set-priority-class.go @@ -0,0 +1,81 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +//nolint:dupl +package actions + +import ( + "fmt" + "strings" + + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +type SetPriorityClass struct { + Expr common.Expression + Cond string + CondTest string + Comment string +} + +func (f *SetPriorityClass) Parse(parts []string, parserType types.ParserType, comment string) error { + if comment != "" { + f.Comment = comment + } + if len(parts) < 3 { + return fmt.Errorf("not enough params") + } + var command []string + switch parserType { + case types.HTTP: + command = parts[2:] + case types.TCP: + command = parts[3:] + } + command, condition := common.SplitRequest(command) + if len(command) == 0 { + return errors.ErrInvalidData + } + expr := common.Expression{} + if expr.Parse(command) != nil { + return fmt.Errorf("not enough params") + } + f.Expr = expr + if len(condition) > 1 { + f.Cond = condition[0] + f.CondTest = strings.Join(condition[1:], " ") + } + return nil +} + +func (f *SetPriorityClass) String() string { + var result strings.Builder + result.WriteString("set-priority-class ") + result.WriteString(f.Expr.String()) + if f.Cond != "" { + result.WriteString(" ") + result.WriteString(f.Cond) + result.WriteString(" ") + result.WriteString(f.CondTest) + } + return result.String() +} + +func (f *SetPriorityClass) GetComment() string { + return f.Comment +} diff --git a/config-parser/parsers/actions/set-priority-offset.go b/config-parser/parsers/actions/set-priority-offset.go new file mode 100644 index 00000000..b72237e3 --- /dev/null +++ b/config-parser/parsers/actions/set-priority-offset.go @@ -0,0 +1,81 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +//nolint:dupl +package actions + +import ( + "fmt" + "strings" + + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +type SetPriorityOffset struct { + Expr common.Expression + Cond string + CondTest string + Comment string +} + +func (f *SetPriorityOffset) Parse(parts []string, parserType types.ParserType, comment string) error { + if comment != "" { + f.Comment = comment + } + if len(parts) < 3 { + return fmt.Errorf("not enough params") + } + var command []string + switch parserType { + case types.HTTP: + command = parts[2:] + case types.TCP: + command = parts[3:] + } + command, condition := common.SplitRequest(command) + if len(command) == 0 { + return errors.ErrInvalidData + } + expr := common.Expression{} + if expr.Parse(command) != nil { + return fmt.Errorf("not enough params") + } + f.Expr = expr + if len(condition) > 1 { + f.Cond = condition[0] + f.CondTest = strings.Join(condition[1:], " ") + } + return nil +} + +func (f *SetPriorityOffset) String() string { + var result strings.Builder + result.WriteString("set-priority-offset ") + result.WriteString(f.Expr.String()) + if f.Cond != "" { + result.WriteString(" ") + result.WriteString(f.Cond) + result.WriteString(" ") + result.WriteString(f.CondTest) + } + return result.String() +} + +func (f *SetPriorityOffset) GetComment() string { + return f.Comment +} diff --git a/config-parser/parsers/actions/set-src-port.go b/config-parser/parsers/actions/set-src-port.go new file mode 100644 index 00000000..3f0ce541 --- /dev/null +++ b/config-parser/parsers/actions/set-src-port.go @@ -0,0 +1,84 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package actions + +import ( + "fmt" + "strings" + + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +type SetSrcPort struct { + Expr common.Expression + Cond string + CondTest string + Comment string +} + +func (f *SetSrcPort) Parse(parts []string, parserType types.ParserType, comment string) error { + if comment != "" { + f.Comment = comment + } + + var command []string + switch parserType { + case types.HTTP: + command = parts[2:] + case types.TCP: + command = parts[3:] + } + + if len(parts) >= 1 { + var condition []string + command, condition = common.SplitRequest(command) + if len(command) == 0 { + return errors.ErrInvalidData + } + expr := common.Expression{} + err := expr.Parse(command) + if err != nil { + return fmt.Errorf("not enough params") + } + f.Expr = expr + if len(condition) > 1 { + f.Cond = condition[0] + f.CondTest = strings.Join(condition[1:], " ") + } + return nil + } + return fmt.Errorf("not enough params") +} + +func (f *SetSrcPort) String() string { + var result strings.Builder + result.WriteString("set-src-port ") + result.WriteString(f.Expr.String()) + if f.Cond != "" { + result.WriteString(" ") + result.WriteString(f.Cond) + result.WriteString(" ") + result.WriteString(f.CondTest) + } + return result.String() +} + +func (f *SetSrcPort) GetComment() string { + return f.Comment +} diff --git a/config-parser/parsers/actions/set-tos.go b/config-parser/parsers/actions/set-tos.go new file mode 100644 index 00000000..3f189d7c --- /dev/null +++ b/config-parser/parsers/actions/set-tos.go @@ -0,0 +1,79 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +//nolint:dupl +package actions + +import ( + "fmt" + "strings" + + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +type SetTos struct { + Value string + Cond string + CondTest string + Comment string +} + +func (f *SetTos) Parse(parts []string, parserType types.ParserType, comment string) error { + if comment != "" { + f.Comment = comment + } + + var command []string + switch parserType { + case types.HTTP: + command = parts[2:] + case types.TCP: + command = parts[3:] + } + if len(parts) >= 1 { + var condition []string + command, condition = common.SplitRequest(command) + if len(command) == 0 { + return errors.ErrInvalidData + } + f.Value = command[0] + if len(condition) > 1 { + f.Cond = condition[0] + f.CondTest = strings.Join(condition[1:], " ") + } + return nil + } + return fmt.Errorf("not enough params") +} + +func (f *SetTos) String() string { + var result strings.Builder + result.WriteString("set-tos ") + result.WriteString(f.Value) + if f.Cond != "" { + result.WriteString(" ") + result.WriteString(f.Cond) + result.WriteString(" ") + result.WriteString(f.CondTest) + } + return result.String() +} + +func (f *SetTos) GetComment() string { + return f.Comment +} diff --git a/config-parser/parsers/actions/set-var-check.go b/config-parser/parsers/actions/set-var-check.go new file mode 100644 index 00000000..fea7416f --- /dev/null +++ b/config-parser/parsers/actions/set-var-check.go @@ -0,0 +1,78 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +//nolint:dupl +package actions + +import ( + "fmt" + "strings" + + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +type SetVarCheck struct { + VarScope string + VarName string + Expr common.Expression + Comment string +} + +func (f *SetVarCheck) Parse(parts []string, parserType types.ParserType, comment string) error { + if comment != "" { + f.Comment = comment + } + if len(parts) < 3 { + return fmt.Errorf("not enough params") + } + var data string + var command []string + + data = parts[1] + command = parts[2:] + + data = strings.TrimPrefix(data, "set-var(") + data = strings.TrimRight(data, ")") + d := strings.SplitN(data, ".", 2) + f.VarScope = d[0] + f.VarName = d[1] + command, condition := common.SplitRequest(command) + if len(command) > 0 { + expr := common.Expression{} + err := expr.Parse(command) + if err != nil { + return fmt.Errorf("not enough params") + } + f.Expr = expr + } else { + return fmt.Errorf("not enough params") + } + if len(condition) > 1 { + return errors.ErrInvalidData + } + + return nil +} + +func (f *SetVarCheck) String() string { + return fmt.Sprintf("set-var(%s.%s) %s", f.VarScope, f.VarName, f.Expr.String()) +} + +func (f *SetVarCheck) GetComment() string { + return f.Comment +} diff --git a/config-parser/parsers/actions/set-var-fmt.go b/config-parser/parsers/actions/set-var-fmt.go new file mode 100644 index 00000000..0eced9da --- /dev/null +++ b/config-parser/parsers/actions/set-var-fmt.go @@ -0,0 +1,85 @@ +/* +Copyright 2022 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +//nolint:dupl +package actions + +import ( + "fmt" + "strings" + + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +type SetVarFmt struct { + VarScope string + VarName string + Fmt common.Expression + Cond string + CondTest string + Comment string +} + +func (f *SetVarFmt) Parse(parts []string, parserType types.ParserType, comment string) error { + if comment != "" { + f.Comment = comment + } + if len(parts) < 3 { + return fmt.Errorf("not enough params") + } + var data string + var command []string + switch parserType { + case types.HTTP: + data = parts[1] + command = parts[2:] + case types.TCP: + data = parts[2] + command = parts[3:] + } + data = strings.TrimPrefix(data, "set-var-fmt(") + data = strings.TrimRight(data, ")") + d := strings.SplitN(data, ".", 2) + f.VarScope = d[0] + f.VarName = d[1] + command, condition := common.SplitRequest(command) + if len(command) > 0 { + expr := common.Expression{} + err := expr.Parse(command) + if err != nil { + return fmt.Errorf("not enough params") + } + f.Fmt = expr + } + if len(condition) > 1 { + f.Cond = condition[0] + f.CondTest = strings.Join(condition[1:], " ") + } + return nil +} + +func (f *SetVarFmt) String() string { + condition := "" + if f.Cond != "" { + condition = fmt.Sprintf(" %s %s", f.Cond, f.CondTest) + } + return fmt.Sprintf("set-var-fmt(%s.%s) %s%s", f.VarScope, f.VarName, f.Fmt.String(), condition) +} + +func (f *SetVarFmt) GetComment() string { + return f.Comment +} diff --git a/config-parser/parsers/actions/set-var.go b/config-parser/parsers/actions/set-var.go new file mode 100644 index 00000000..5980603a --- /dev/null +++ b/config-parser/parsers/actions/set-var.go @@ -0,0 +1,85 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +//nolint:dupl +package actions + +import ( + "fmt" + "strings" + + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +type SetVar struct { + VarScope string + VarName string + Expr common.Expression + Cond string + CondTest string + Comment string +} + +func (f *SetVar) Parse(parts []string, parserType types.ParserType, comment string) error { + if comment != "" { + f.Comment = comment + } + if len(parts) < 3 { + return fmt.Errorf("not enough params") + } + var data string + var command []string + switch parserType { + case types.HTTP: + data = parts[1] + command = parts[2:] + case types.TCP: + data = parts[2] + command = parts[3:] + } + data = strings.TrimPrefix(data, "set-var(") + data = strings.TrimRight(data, ")") + d := strings.SplitN(data, ".", 2) + f.VarScope = d[0] + f.VarName = d[1] + command, condition := common.SplitRequest(command) + if len(command) > 0 { + expr := common.Expression{} + err := expr.Parse(command) + if err != nil { + return fmt.Errorf("not enough params") + } + f.Expr = expr + } + if len(condition) > 1 { + f.Cond = condition[0] + f.CondTest = strings.Join(condition[1:], " ") + } + return nil +} + +func (f *SetVar) String() string { + condition := "" + if f.Cond != "" { + condition = fmt.Sprintf(" %s %s", f.Cond, f.CondTest) + } + return fmt.Sprintf("set-var(%s.%s) %s%s", f.VarScope, f.VarName, f.Expr.String(), condition) +} + +func (f *SetVar) GetComment() string { + return f.Comment +} diff --git a/config-parser/parsers/actions/silent-drop.go b/config-parser/parsers/actions/silent-drop.go new file mode 100644 index 00000000..92b07659 --- /dev/null +++ b/config-parser/parsers/actions/silent-drop.go @@ -0,0 +1,86 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package actions + +import ( + stderrors "errors" + "strconv" + "strings" + + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +type SilentDrop struct { + RstTTL int64 + Cond string + CondTest string + Comment string +} + +func (f *SilentDrop) Parse(parts []string, parserType types.ParserType, comment string) error { + if comment != "" { + f.Comment = comment + } + if len(parts) < 2 { + return stderrors.New("not enough params") + } + var command []string + switch parserType { + case types.HTTP: + command = parts[2:] + case types.TCP: + command = parts[3:] + } + command, condition := common.SplitRequest(command) + if len(condition) > 1 { + f.Cond = condition[0] + f.CondTest = strings.Join(condition[1:], " ") + } + if len(command) > 0 && command[0] == "rst-ttl" { + if len(command) <= 1 { + return stderrors.New("missing rst-ttl value") + } + rstTTL, err := strconv.ParseInt(command[1], 10, 64) + if err != nil { + return &errors.ParseError{Parser: "SilentDrop", Message: err.Error()} + } + f.RstTTL = rstTTL + } + return nil +} + +func (f *SilentDrop) String() string { + var result strings.Builder + result.WriteString("silent-drop") + if f.RstTTL > 0 { + result.WriteString(" rst-ttl ") + result.WriteString(strconv.FormatInt(f.RstTTL, 10)) + } + if f.Cond != "" { + result.WriteString(" ") + result.WriteString(f.Cond) + result.WriteString(" ") + result.WriteString(f.CondTest) + } + return result.String() +} + +func (f *SilentDrop) GetComment() string { + return f.Comment +} diff --git a/config-parser/parsers/actions/track-sc.go b/config-parser/parsers/actions/track-sc.go new file mode 100644 index 00000000..a4105241 --- /dev/null +++ b/config-parser/parsers/actions/track-sc.go @@ -0,0 +1,125 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package actions + +import ( + "fmt" + "strconv" + "strings" + + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +type TrackScT string + +const ( + TrackScType TrackScT = "track-sc" +) + +type TrackSc struct { + Type TrackScT + StickCounter int64 + Key string + Table string + Comment string + Cond string + CondTest string +} + +func (f *TrackSc) Parse(parts []string, parserType types.ParserType, comment string) error { + if comment != "" { + f.Comment = comment + } + var data string + var command []string + switch parserType { + case types.HTTP: + if len(parts) < 3 { + return fmt.Errorf("not enough params") + } + data = parts[1] + command = parts[2:] + case types.TCP: + if len(parts) < 4 { + return fmt.Errorf("not enough params") + } + data = parts[2] + command = parts[3:] + } + + f.Type = TrackScType + counterS := strings.TrimPrefix(data, string(TrackScType)) + counter, err := strconv.ParseInt(counterS, 10, 64) + if err != nil { + return fmt.Errorf("failed to parse stick-counter") + } + f.StickCounter = counter + + return f.parseCommand(command) +} + +func (f *TrackSc) parseCommand(command []string) error { + // command contains only + if len(command) == 1 { + f.Key = command[0] + return nil + } + + if len(command) < 3 { + return fmt.Errorf("not enough params") + } + command, condition := common.SplitRequest(command) + if len(command) > 1 && command[1] == "table" { + if len(command) < 3 { + return fmt.Errorf("not enough params") + } + f.Key = command[0] + f.Table = command[2] + } + if len(command) == 1 { + f.Key = command[0] + } + if len(condition) > 1 { + f.Cond = condition[0] + f.CondTest = strings.Join(condition[1:], " ") + } + return nil +} + +func (f *TrackSc) String() string { + var result strings.Builder + result.WriteString(string(f.Type)) + result.WriteString(strconv.FormatInt(f.StickCounter, 10)) + result.WriteString(" ") + result.WriteString(f.Key) + if f.Table != "" { + result.WriteString(" table ") + result.WriteString(f.Table) + } + if f.Cond != "" { + result.WriteString(" ") + result.WriteString(f.Cond) + result.WriteString(" ") + result.WriteString(f.CondTest) + } + return result.String() +} + +func (f *TrackSc) GetComment() string { + return f.Comment +} diff --git a/config-parser/parsers/actions/unset-var-check.go b/config-parser/parsers/actions/unset-var-check.go new file mode 100644 index 00000000..fb85f811 --- /dev/null +++ b/config-parser/parsers/actions/unset-var-check.go @@ -0,0 +1,75 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package actions + +import ( + "fmt" + "strings" + + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +type UnsetVarCheck struct { + Scope string + Name string + Comment string +} + +func (f *UnsetVarCheck) Parse(parts []string, parserType types.ParserType, comment string) error { + if comment != "" { + f.Comment = comment + } + if len(parts) < 2 { + return fmt.Errorf("not enough params") + } + var data string + var command []string + + data = parts[1] + command = parts[2:] + + data = strings.TrimPrefix(data, "unset-var(") + data = strings.TrimRight(data, ")") + d := strings.SplitN(data, ".", 2) + if len(d) < 2 || len(d[1]) == 0 { + return errors.ErrInvalidData + } + f.Scope = d[0] + f.Name = d[1] + // no condition on http-check and tcp-check unset-var + _, condition := common.SplitRequest(command) + if len(condition) > 1 { + return errors.ErrInvalidData + } + return nil +} + +func (f *UnsetVarCheck) String() string { + var result strings.Builder + result.WriteString("unset-var(") + result.WriteString(f.Scope) + result.WriteString(".") + result.WriteString(f.Name) + result.WriteString(")") + return result.String() +} + +func (f *UnsetVarCheck) GetComment() string { + return f.Comment +} diff --git a/config-parser/parsers/actions/unset-var.go b/config-parser/parsers/actions/unset-var.go new file mode 100644 index 00000000..9966566f --- /dev/null +++ b/config-parser/parsers/actions/unset-var.go @@ -0,0 +1,87 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package actions + +import ( + "fmt" + "strings" + + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +type UnsetVar struct { + Scope string + Name string + Cond string + CondTest string + Comment string +} + +func (f *UnsetVar) Parse(parts []string, parserType types.ParserType, comment string) error { + if comment != "" { + f.Comment = comment + } + if len(parts) < 2 { + return fmt.Errorf("not enough params") + } + var data string + var command []string + switch parserType { + case types.HTTP: + data = parts[1] + command = parts[2:] + case types.TCP: + data = parts[2] + command = parts[3:] + } + data = strings.TrimPrefix(data, "unset-var(") + data = strings.TrimRight(data, ")") + d := strings.SplitN(data, ".", 2) + if len(d) < 2 || len(d[1]) == 0 { + return errors.ErrInvalidData + } + f.Scope = d[0] + f.Name = d[1] + _, condition := common.SplitRequest(command) + if len(condition) > 1 { + f.Cond = condition[0] + f.CondTest = strings.Join(condition[1:], " ") + } + return nil +} + +func (f *UnsetVar) String() string { + var result strings.Builder + result.WriteString("unset-var(") + result.WriteString(f.Scope) + result.WriteString(".") + result.WriteString(f.Name) + result.WriteString(")") + if f.Cond != "" { + result.WriteString(" ") + result.WriteString(f.Cond) + result.WriteString(" ") + result.WriteString(f.CondTest) + } + return result.String() +} + +func (f *UnsetVar) GetComment() string { + return f.Comment +} diff --git a/config-parser/parsers/actions/use-service.go b/config-parser/parsers/actions/use-service.go new file mode 100644 index 00000000..345f41d0 --- /dev/null +++ b/config-parser/parsers/actions/use-service.go @@ -0,0 +1,71 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package actions + +import ( + "fmt" + "strings" + + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +type UseService struct { + Name string + Cond string + CondTest string + Comment string +} + +// Parse parses http-request user-service [ { if | unless } ] +func (us *UseService) Parse(parts []string, parserType types.ParserType, comment string) error { + if comment != "" { + us.Comment = comment + } + if len(parts) < 3 { + return fmt.Errorf("not enough params") + } + var data string + var command []string + switch parserType { + case types.HTTP: + data = parts[2] + command = parts[3:] + case types.TCP: + data = parts[3] + command = parts[4:] + } + _, condition := common.SplitRequest(command) + us.Name = data + if len(condition) > 1 { + us.Cond = condition[0] + us.CondTest = strings.Join(condition[1:], " ") + } + return nil +} + +func (us *UseService) String() string { + condition := "" + if us.Cond != "" { + condition = fmt.Sprintf(" %s %s", us.Cond, us.CondTest) + } + return fmt.Sprintf("use-service %s%s", us.Name, condition) +} + +func (us *UseService) GetComment() string { + return us.Comment +} diff --git a/config-parser/parsers/balance.go b/config-parser/parsers/balance.go new file mode 100644 index 00000000..b37200d3 --- /dev/null +++ b/config-parser/parsers/balance.go @@ -0,0 +1,120 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package parsers + +import ( + "fmt" + "strings" + + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/params" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +type Balance struct { + data *types.Balance + preComments []string // comments that appear before the actual line +} + +func (p *Balance) parseBalanceParams(pb params.BalanceParams, line string, parts []string) (*types.Balance, error) { + if len(parts) >= 2 { + b, err := pb.Parse(parts[1:]) + if err != nil { + return nil, &errors.ParseError{Parser: "Balance", Line: line} + } + data := &types.Balance{ + Params: b, + } + return data, nil + } + + return nil, &errors.ParseError{Parser: "Balance", Line: line} +} + +func (p *Balance) Parse(line string, parts []string, comment string) (string, error) { + if parts[0] == "balance" { + if len(parts) < 2 { + return "", &errors.ParseError{Parser: "Balance", Line: line} + } + + data := &types.Balance{ + Comment: comment, + } + + var err error + var pb *types.Balance + + switch parts[1] { + case "roundrobin", "static-rr", "leastconn", "first", "source", "random", "rdp-cookie": + data.Algorithm = parts[1] + case "uri": + pb, err = p.parseBalanceParams(¶ms.BalanceURI{}, line, parts) + data.Algorithm = parts[1] + case "url_param": + pb, err = p.parseBalanceParams(¶ms.BalanceURLParam{}, line, parts) + data.Algorithm = parts[1] + default: + switch { + case parts[1] == "hash": + pb, err = p.parseBalanceParams(¶ms.BalanceHash{}, line, parts) + data.Algorithm = parts[1] + case strings.HasPrefix(parts[1], "random(") && strings.HasSuffix(parts[1], ")"): + pb, err = p.parseBalanceParams(¶ms.BalanceRandom{}, line, parts) + data.Algorithm = "random" + case strings.HasPrefix(parts[1], "rdp-cookie(") && strings.HasSuffix(parts[1], ")"): + pb, err = p.parseBalanceParams(¶ms.BalanceRdpCookie{}, line, parts) + data.Algorithm = "rdp-cookie" + case strings.HasPrefix(parts[1], "hdr(") && strings.HasSuffix(parts[1], ")"): + pb, err = p.parseBalanceParams(¶ms.BalanceHdr{}, line, parts) + data.Algorithm = "hdr" + default: + return "", &errors.ParseError{Parser: "Balance", Line: line} + } + } + + if err != nil { + return "", &errors.ParseError{Parser: "Balance", Line: line} + } + + if pb != nil && pb.Params != nil { + data.Params = pb.Params + } + + p.data = data + return "", nil + } + return "", &errors.ParseError{Parser: "Balance", Line: line} +} + +func (p *Balance) Result() ([]common.ReturnResultLine, error) { + if p.data == nil { + return nil, errors.ErrFetch + } + + params := "" + if p.data.Params != nil { + params = p.data.Params.String() + } + + return []common.ReturnResultLine{ + { + Data: fmt.Sprintf("balance %s%s", p.data.Algorithm, params), + Comment: p.data.Comment, + }, + }, nil +} diff --git a/config-parser/parsers/balance_generated.go b/config-parser/parsers/balance_generated.go new file mode 100644 index 00000000..e2f7b75d --- /dev/null +++ b/config-parser/parsers/balance_generated.go @@ -0,0 +1,99 @@ +// Code generated by go generate; DO NOT EDIT. +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package parsers + +import ( + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +func (p *Balance) Init() { + p.data = nil + p.preComments = []string{} +} + +func (p *Balance) GetParserName() string { + return "balance" +} + +func (p *Balance) Get(createIfNotExist bool) (common.ParserData, error) { + if p.data == nil { + if createIfNotExist { + p.data = &types.Balance{} + return p.data, nil + } + return nil, errors.ErrFetch + } + return p.data, nil +} + +func (p *Balance) GetPreComments() ([]string, error) { + return p.preComments, nil +} + +func (p *Balance) SetPreComments(preComments []string) { + p.preComments = preComments +} + +func (p *Balance) GetOne(index int) (common.ParserData, error) { + if index > 0 { + return nil, errors.ErrFetch + } + if p.data == nil { + return nil, errors.ErrFetch + } + return p.data, nil +} + +func (p *Balance) Delete(index int) error { + p.Init() + return nil +} + +func (p *Balance) Insert(data common.ParserData, index int) error { + return p.Set(data, index) +} + +func (p *Balance) Set(data common.ParserData, index int) error { + if data == nil { + p.Init() + return nil + } + switch newValue := data.(type) { + case *types.Balance: + p.data = newValue + case types.Balance: + p.data = &newValue + default: + return errors.ErrInvalidData + } + return nil +} + +func (p *Balance) PreParse(line string, parts []string, preComments []string, comment string) (string, error) { + changeState, err := p.Parse(line, parts, comment) + if err == nil && preComments != nil { + p.preComments = append(p.preComments, preComments...) + } + return changeState, err +} + +func (p *Balance) ResultAll() ([]common.ReturnResultLine, []string, error) { + res, err := p.Result() + return res, p.preComments, err +} diff --git a/config-parser/parsers/bind-process.go b/config-parser/parsers/bind-process.go new file mode 100644 index 00000000..d2ab63b8 --- /dev/null +++ b/config-parser/parsers/bind-process.go @@ -0,0 +1,86 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package parsers + +import ( + "fmt" + "strconv" + "strings" + + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +type BindProcess struct { + data *types.BindProcess + preComments []string // comments that appear before the actual line +} + +func (p *BindProcess) Parse(line string, parts []string, comment string) (string, error) { + if parts[0] != "bind-process" || len(parts) < 2 { + return "", &errors.ParseError{Parser: "BindProcess", Line: line, Message: "Parse error"} + } + + switch parts[1] { + case "all", "odd", "even": + p.data = &types.BindProcess{ + Comment: comment, + Process: parts[1], + } + return "", nil + } + + for _, d := range parts[1:] { + if strings.Contains(d, "-") { + if len(parts) > 2 { + return "", &errors.ParseError{Parser: "BindProcess", Line: line} + } + split := common.StringSplitIgnoreEmpty(d, '-') + for _, s := range split { + _, err := strconv.Atoi(s) + if err != nil { + return "", &errors.ParseError{Parser: "BindProcess", Line: line, Message: err.Error()} + } + } + } else { + _, err := strconv.Atoi(d) + if err != nil { + return "", &errors.ParseError{Parser: "BindProcess", Line: line, Message: err.Error()} + } + } + } + + p.data = &types.BindProcess{ + Comment: comment, + Process: strings.Join(parts[1:], " "), + } + return "", nil +} + +func (p *BindProcess) Result() ([]common.ReturnResultLine, error) { + if p.data == nil { + return nil, errors.ErrFetch + } + + return []common.ReturnResultLine{ + { + Data: fmt.Sprintf("bind-process %s", p.data.Process), + Comment: p.data.Comment, + }, + }, nil +} diff --git a/config-parser/parsers/bind-process_generated.go b/config-parser/parsers/bind-process_generated.go new file mode 100644 index 00000000..44375fee --- /dev/null +++ b/config-parser/parsers/bind-process_generated.go @@ -0,0 +1,99 @@ +// Code generated by go generate; DO NOT EDIT. +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package parsers + +import ( + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +func (p *BindProcess) Init() { + p.data = nil + p.preComments = []string{} +} + +func (p *BindProcess) GetParserName() string { + return "bind-process" +} + +func (p *BindProcess) Get(createIfNotExist bool) (common.ParserData, error) { + if p.data == nil { + if createIfNotExist { + p.data = &types.BindProcess{} + return p.data, nil + } + return nil, errors.ErrFetch + } + return p.data, nil +} + +func (p *BindProcess) GetPreComments() ([]string, error) { + return p.preComments, nil +} + +func (p *BindProcess) SetPreComments(preComments []string) { + p.preComments = preComments +} + +func (p *BindProcess) GetOne(index int) (common.ParserData, error) { + if index > 0 { + return nil, errors.ErrFetch + } + if p.data == nil { + return nil, errors.ErrFetch + } + return p.data, nil +} + +func (p *BindProcess) Delete(index int) error { + p.Init() + return nil +} + +func (p *BindProcess) Insert(data common.ParserData, index int) error { + return p.Set(data, index) +} + +func (p *BindProcess) Set(data common.ParserData, index int) error { + if data == nil { + p.Init() + return nil + } + switch newValue := data.(type) { + case *types.BindProcess: + p.data = newValue + case types.BindProcess: + p.data = &newValue + default: + return errors.ErrInvalidData + } + return nil +} + +func (p *BindProcess) PreParse(line string, parts []string, preComments []string, comment string) (string, error) { + changeState, err := p.Parse(line, parts, comment) + if err == nil && preComments != nil { + p.preComments = append(p.preComments, preComments...) + } + return changeState, err +} + +func (p *BindProcess) ResultAll() ([]common.ReturnResultLine, []string, error) { + res, err := p.Result() + return res, p.preComments, err +} diff --git a/config-parser/parsers/bind.go b/config-parser/parsers/bind.go new file mode 100644 index 00000000..28302e8b --- /dev/null +++ b/config-parser/parsers/bind.go @@ -0,0 +1,71 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package parsers + +import ( + "strings" + + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/params" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +type Bind struct { + data []types.Bind + preComments []string // comments that appear before the actual line +} + +func (h *Bind) parse(line string, parts []string, comment string) (*types.Bind, error) { + if len(parts) >= 2 { + data := &types.Bind{ + Path: parts[1], + Comment: comment, + } + if len(parts) > 2 { + paramsBindOptions, err := params.ParseBindOptions(parts[2:]) + if err != nil { + return nil, &errors.ParseError{Parser: "BindLines", Line: line} + } + data.Params = paramsBindOptions + } + return data, nil + } + return nil, &errors.ParseError{Parser: "BindLines", Line: line} +} + +func (h *Bind) Result() ([]common.ReturnResultLine, error) { + if len(h.data) == 0 { + return nil, errors.ErrFetch + } + result := make([]common.ReturnResultLine, len(h.data)) + for index, req := range h.data { + var sb strings.Builder + sb.WriteString("bind ") + sb.WriteString(req.Path) + options := params.BindOptionsString(req.Params) + if options != "" { + sb.WriteString(" ") + sb.WriteString(options) + } + result[index] = common.ReturnResultLine{ + Data: sb.String(), + Comment: req.Comment, + } + } + return result, nil +} diff --git a/config-parser/parsers/bind_generated.go b/config-parser/parsers/bind_generated.go new file mode 100644 index 00000000..8d791c44 --- /dev/null +++ b/config-parser/parsers/bind_generated.go @@ -0,0 +1,157 @@ +// Code generated by go generate; DO NOT EDIT. +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package parsers + +import ( + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +func (p *Bind) Init() { + p.data = []types.Bind{} + p.preComments = []string{} +} + +func (p *Bind) GetParserName() string { + return "bind" +} + +func (p *Bind) Get(createIfNotExist bool) (common.ParserData, error) { + if len(p.data) == 0 && !createIfNotExist { + return nil, errors.ErrFetch + } + return p.data, nil +} + +func (p *Bind) GetPreComments() ([]string, error) { + return p.preComments, nil +} + +func (p *Bind) SetPreComments(preComments []string) { + p.preComments = preComments +} + +func (p *Bind) GetOne(index int) (common.ParserData, error) { + if index < 0 || index >= len(p.data) { + return nil, errors.ErrFetch + } + return p.data[index], nil +} + +func (p *Bind) Delete(index int) error { + if index < 0 || index >= len(p.data) { + return errors.ErrFetch + } + copy(p.data[index:], p.data[index+1:]) + p.data[len(p.data)-1] = types.Bind{} + p.data = p.data[:len(p.data)-1] + return nil +} + +func (p *Bind) Insert(data common.ParserData, index int) error { + if data == nil { + return errors.ErrInvalidData + } + switch newValue := data.(type) { + case []types.Bind: + p.data = newValue + case *types.Bind: + if index > -1 { + if index > len(p.data) { + return errors.ErrIndexOutOfRange + } + p.data = append(p.data, types.Bind{}) + copy(p.data[index+1:], p.data[index:]) + p.data[index] = *newValue + } else { + p.data = append(p.data, *newValue) + } + case types.Bind: + if index > -1 { + if index > len(p.data) { + return errors.ErrIndexOutOfRange + } + p.data = append(p.data, types.Bind{}) + copy(p.data[index+1:], p.data[index:]) + p.data[index] = newValue + } else { + p.data = append(p.data, newValue) + } + default: + return errors.ErrInvalidData + } + return nil +} + +func (p *Bind) Set(data common.ParserData, index int) error { + if data == nil { + p.Init() + return nil + } + switch newValue := data.(type) { + case []types.Bind: + p.data = newValue + case *types.Bind: + if index > -1 && index < len(p.data) { + p.data[index] = *newValue + } else if index == -1 { + p.data = append(p.data, *newValue) + } else { + return errors.ErrIndexOutOfRange + } + case types.Bind: + if index > -1 && index < len(p.data) { + p.data[index] = newValue + } else if index == -1 { + p.data = append(p.data, newValue) + } else { + return errors.ErrIndexOutOfRange + } + default: + return errors.ErrInvalidData + } + return nil +} + +func (p *Bind) PreParse(line string, parts []string, preComments []string, comment string) (string, error) { + changeState, err := p.Parse(line, parts, comment) + if err == nil && preComments != nil { + p.preComments = append(p.preComments, preComments...) + } + return changeState, err +} + +func (p *Bind) Parse(line string, parts []string, comment string) (string, error) { + if parts[0] == "bind" { + data, err := p.parse(line, parts, comment) + if err != nil { + if _, ok := err.(*errors.ParseError); ok { + return "", err + } + return "", &errors.ParseError{Parser: "Bind", Line: line} + } + p.data = append(p.data, *data) + return "", nil + } + return "", &errors.ParseError{Parser: "Bind", Line: line} +} + +func (p *Bind) ResultAll() ([]common.ReturnResultLine, []string, error) { + res, err := p.Result() + return res, p.preComments, err +} diff --git a/config-parser/parsers/command.go b/config-parser/parsers/command.go new file mode 100644 index 00000000..93d1def1 --- /dev/null +++ b/config-parser/parsers/command.go @@ -0,0 +1,65 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package parsers + +import ( + "fmt" + "strings" + + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +type Command struct { + data *types.Command + preComments []string +} + +func (p *Command) Parse(line string, parts []string, comment string) (string, error) { + if len(parts) < 2 { + return "", &errors.ParseError{Parser: "Command", Line: line, Message: "missing command"} + } + + if parts[0] != "command" { + return "", &errors.ParseError{Parser: "Command", Line: line, Message: fmt.Sprintf("expected command, got %s", parts[0])} + } + + p.data = &types.Command{ + Args: strings.Join(parts[1:], " "), + Comment: comment, + } + return "", nil +} + +func (p *Command) Result() ([]common.ReturnResultLine, error) { + if p.data == nil { + return nil, errors.ErrFetch + } + + var sb strings.Builder + + sb.WriteString("command ") + sb.WriteString(p.data.Args) + + return []common.ReturnResultLine{ + { + Data: sb.String(), + Comment: p.data.Comment, + }, + }, nil +} diff --git a/config-parser/parsers/command_generated.go b/config-parser/parsers/command_generated.go new file mode 100644 index 00000000..5ceba44b --- /dev/null +++ b/config-parser/parsers/command_generated.go @@ -0,0 +1,99 @@ +// Code generated by go generate; DO NOT EDIT. +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package parsers + +import ( + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +func (p *Command) Init() { + p.data = nil + p.preComments = []string{} +} + +func (p *Command) GetParserName() string { + return "command" +} + +func (p *Command) Get(createIfNotExist bool) (common.ParserData, error) { + if p.data == nil { + if createIfNotExist { + p.data = &types.Command{} + return p.data, nil + } + return nil, errors.ErrFetch + } + return p.data, nil +} + +func (p *Command) GetPreComments() ([]string, error) { + return p.preComments, nil +} + +func (p *Command) SetPreComments(preComments []string) { + p.preComments = preComments +} + +func (p *Command) GetOne(index int) (common.ParserData, error) { + if index > 0 { + return nil, errors.ErrFetch + } + if p.data == nil { + return nil, errors.ErrFetch + } + return p.data, nil +} + +func (p *Command) Delete(index int) error { + p.Init() + return nil +} + +func (p *Command) Insert(data common.ParserData, index int) error { + return p.Set(data, index) +} + +func (p *Command) Set(data common.ParserData, index int) error { + if data == nil { + p.Init() + return nil + } + switch newValue := data.(type) { + case *types.Command: + p.data = newValue + case types.Command: + p.data = &newValue + default: + return errors.ErrInvalidData + } + return nil +} + +func (p *Command) PreParse(line string, parts []string, preComments []string, comment string) (string, error) { + changeState, err := p.Parse(line, parts, comment) + if err == nil && preComments != nil { + p.preComments = append(p.preComments, preComments...) + } + return changeState, err +} + +func (p *Command) ResultAll() ([]common.ReturnResultLine, []string, error) { + res, err := p.Result() + return res, p.preComments, err +} diff --git a/config-parser/parsers/compression-algo-req.go b/config-parser/parsers/compression-algo-req.go new file mode 100644 index 00000000..bfecc53a --- /dev/null +++ b/config-parser/parsers/compression-algo-req.go @@ -0,0 +1,53 @@ +/* +Copyright 2022 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package parsers + +import ( + "fmt" + + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +type CompressionAlgoReq struct { + data *types.StringC + preComments []string // comments that appear before the actual line +} + +func (c *CompressionAlgoReq) Parse(line string, parts []string, comment string) (string, error) { + if len(parts) < 3 { + return "", &errors.ParseError{Parser: "CompressionAlgoReq", Line: line, Message: "Parse error"} + } + c.data = &types.StringC{ + Value: parts[2], + Comment: comment, + } + return "", nil +} + +func (c *CompressionAlgoReq) Result() ([]common.ReturnResultLine, error) { + if c.data == nil { + return nil, errors.ErrFetch + } + return []common.ReturnResultLine{ + { + Data: fmt.Sprintf("compression algo-req %s", c.data.Value), + Comment: c.data.Comment, + }, + }, nil +} diff --git a/config-parser/parsers/compression-algo-req_generated.go b/config-parser/parsers/compression-algo-req_generated.go new file mode 100644 index 00000000..ddc84f6a --- /dev/null +++ b/config-parser/parsers/compression-algo-req_generated.go @@ -0,0 +1,99 @@ +// Code generated by go generate; DO NOT EDIT. +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package parsers + +import ( + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +func (p *CompressionAlgoReq) Init() { + p.data = nil + p.preComments = []string{} +} + +func (p *CompressionAlgoReq) GetParserName() string { + return "compression algo-req" +} + +func (p *CompressionAlgoReq) Get(createIfNotExist bool) (common.ParserData, error) { + if p.data == nil { + if createIfNotExist { + p.data = &types.StringC{} + return p.data, nil + } + return nil, errors.ErrFetch + } + return p.data, nil +} + +func (p *CompressionAlgoReq) GetPreComments() ([]string, error) { + return p.preComments, nil +} + +func (p *CompressionAlgoReq) SetPreComments(preComments []string) { + p.preComments = preComments +} + +func (p *CompressionAlgoReq) GetOne(index int) (common.ParserData, error) { + if index > 0 { + return nil, errors.ErrFetch + } + if p.data == nil { + return nil, errors.ErrFetch + } + return p.data, nil +} + +func (p *CompressionAlgoReq) Delete(index int) error { + p.Init() + return nil +} + +func (p *CompressionAlgoReq) Insert(data common.ParserData, index int) error { + return p.Set(data, index) +} + +func (p *CompressionAlgoReq) Set(data common.ParserData, index int) error { + if data == nil { + p.Init() + return nil + } + switch newValue := data.(type) { + case *types.StringC: + p.data = newValue + case types.StringC: + p.data = &newValue + default: + return errors.ErrInvalidData + } + return nil +} + +func (p *CompressionAlgoReq) PreParse(line string, parts []string, preComments []string, comment string) (string, error) { + changeState, err := p.Parse(line, parts, comment) + if err == nil && preComments != nil { + p.preComments = append(p.preComments, preComments...) + } + return changeState, err +} + +func (p *CompressionAlgoReq) ResultAll() ([]common.ReturnResultLine, []string, error) { + res, err := p.Result() + return res, p.preComments, err +} diff --git a/config-parser/parsers/compression-algo-res.go b/config-parser/parsers/compression-algo-res.go new file mode 100644 index 00000000..61325d80 --- /dev/null +++ b/config-parser/parsers/compression-algo-res.go @@ -0,0 +1,61 @@ +/* +Copyright 2022 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package parsers + +import ( + "strings" + + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +type CompressionAlgoRes struct { + data *types.StringSliceC + preComments []string // comments that appear before the actual line +} + +func (c *CompressionAlgoRes) Parse(line string, parts []string, comment string) (string, error) { + if len(parts) < 3 { + return "", &errors.ParseError{Parser: "CompressionAlgoRes", Line: line, Message: "Parse error"} + } + c.data = &types.StringSliceC{ + Value: parts[2:], + Comment: comment, + } + return "", nil +} + +func (c *CompressionAlgoRes) Result() ([]common.ReturnResultLine, error) { + if c.data == nil || len(c.data.Value) == 0 { + return nil, errors.ErrFetch + } + var result strings.Builder + result.WriteString("compression algo-res") + + for _, typereq := range c.data.Value { + result.WriteString(" ") + result.WriteString(typereq) + } + + return []common.ReturnResultLine{ + { + Data: result.String(), + Comment: c.data.Comment, + }, + }, nil +} diff --git a/config-parser/parsers/compression-algo-res_generated.go b/config-parser/parsers/compression-algo-res_generated.go new file mode 100644 index 00000000..725969c9 --- /dev/null +++ b/config-parser/parsers/compression-algo-res_generated.go @@ -0,0 +1,99 @@ +// Code generated by go generate; DO NOT EDIT. +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package parsers + +import ( + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +func (p *CompressionAlgoRes) Init() { + p.data = nil + p.preComments = []string{} +} + +func (p *CompressionAlgoRes) GetParserName() string { + return "compression algo-res" +} + +func (p *CompressionAlgoRes) Get(createIfNotExist bool) (common.ParserData, error) { + if p.data == nil { + if createIfNotExist { + p.data = &types.StringSliceC{} + return p.data, nil + } + return nil, errors.ErrFetch + } + return p.data, nil +} + +func (p *CompressionAlgoRes) GetPreComments() ([]string, error) { + return p.preComments, nil +} + +func (p *CompressionAlgoRes) SetPreComments(preComments []string) { + p.preComments = preComments +} + +func (p *CompressionAlgoRes) GetOne(index int) (common.ParserData, error) { + if index > 0 { + return nil, errors.ErrFetch + } + if p.data == nil { + return nil, errors.ErrFetch + } + return p.data, nil +} + +func (p *CompressionAlgoRes) Delete(index int) error { + p.Init() + return nil +} + +func (p *CompressionAlgoRes) Insert(data common.ParserData, index int) error { + return p.Set(data, index) +} + +func (p *CompressionAlgoRes) Set(data common.ParserData, index int) error { + if data == nil { + p.Init() + return nil + } + switch newValue := data.(type) { + case *types.StringSliceC: + p.data = newValue + case types.StringSliceC: + p.data = &newValue + default: + return errors.ErrInvalidData + } + return nil +} + +func (p *CompressionAlgoRes) PreParse(line string, parts []string, preComments []string, comment string) (string, error) { + changeState, err := p.Parse(line, parts, comment) + if err == nil && preComments != nil { + p.preComments = append(p.preComments, preComments...) + } + return changeState, err +} + +func (p *CompressionAlgoRes) ResultAll() ([]common.ReturnResultLine, []string, error) { + res, err := p.Result() + return res, p.preComments, err +} diff --git a/config-parser/parsers/compression-algo.go b/config-parser/parsers/compression-algo.go new file mode 100644 index 00000000..45bdb8df --- /dev/null +++ b/config-parser/parsers/compression-algo.go @@ -0,0 +1,61 @@ +/* +Copyright 2022 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package parsers + +import ( + "strings" + + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +type CompressionAlgo struct { + data *types.StringSliceC + preComments []string // comments that appear before the actual line +} + +func (c *CompressionAlgo) Parse(line string, parts []string, comment string) (string, error) { + if len(parts) < 3 { + return "", &errors.ParseError{Parser: "CompressionAlgo", Line: line, Message: "Parse error"} + } + c.data = &types.StringSliceC{ + Value: parts[2:], + Comment: comment, + } + return "", nil +} + +func (c *CompressionAlgo) Result() ([]common.ReturnResultLine, error) { + if c.data == nil || len(c.data.Value) == 0 { + return nil, errors.ErrFetch + } + var result strings.Builder + result.WriteString("compression algo") + + for _, algo := range c.data.Value { + result.WriteString(" ") + result.WriteString(algo) + } + + return []common.ReturnResultLine{ + { + Data: result.String(), + Comment: c.data.Comment, + }, + }, nil +} diff --git a/config-parser/parsers/compression-algo_generated.go b/config-parser/parsers/compression-algo_generated.go new file mode 100644 index 00000000..be4deb36 --- /dev/null +++ b/config-parser/parsers/compression-algo_generated.go @@ -0,0 +1,99 @@ +// Code generated by go generate; DO NOT EDIT. +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package parsers + +import ( + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +func (p *CompressionAlgo) Init() { + p.data = nil + p.preComments = []string{} +} + +func (p *CompressionAlgo) GetParserName() string { + return "compression algo" +} + +func (p *CompressionAlgo) Get(createIfNotExist bool) (common.ParserData, error) { + if p.data == nil { + if createIfNotExist { + p.data = &types.StringSliceC{} + return p.data, nil + } + return nil, errors.ErrFetch + } + return p.data, nil +} + +func (p *CompressionAlgo) GetPreComments() ([]string, error) { + return p.preComments, nil +} + +func (p *CompressionAlgo) SetPreComments(preComments []string) { + p.preComments = preComments +} + +func (p *CompressionAlgo) GetOne(index int) (common.ParserData, error) { + if index > 0 { + return nil, errors.ErrFetch + } + if p.data == nil { + return nil, errors.ErrFetch + } + return p.data, nil +} + +func (p *CompressionAlgo) Delete(index int) error { + p.Init() + return nil +} + +func (p *CompressionAlgo) Insert(data common.ParserData, index int) error { + return p.Set(data, index) +} + +func (p *CompressionAlgo) Set(data common.ParserData, index int) error { + if data == nil { + p.Init() + return nil + } + switch newValue := data.(type) { + case *types.StringSliceC: + p.data = newValue + case types.StringSliceC: + p.data = &newValue + default: + return errors.ErrInvalidData + } + return nil +} + +func (p *CompressionAlgo) PreParse(line string, parts []string, preComments []string, comment string) (string, error) { + changeState, err := p.Parse(line, parts, comment) + if err == nil && preComments != nil { + p.preComments = append(p.preComments, preComments...) + } + return changeState, err +} + +func (p *CompressionAlgo) ResultAll() ([]common.ReturnResultLine, []string, error) { + res, err := p.Result() + return res, p.preComments, err +} diff --git a/config-parser/parsers/compression-direction.go b/config-parser/parsers/compression-direction.go new file mode 100644 index 00000000..8c6c91da --- /dev/null +++ b/config-parser/parsers/compression-direction.go @@ -0,0 +1,53 @@ +/* +Copyright 2022 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package parsers + +import ( + "fmt" + + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +type CompressionDirection struct { + data *types.StringC + preComments []string // comments that appear before the actual line +} + +func (c *CompressionDirection) Parse(line string, parts []string, comment string) (string, error) { + if len(parts) < 3 { + return "", &errors.ParseError{Parser: "CompressionDirection", Line: line, Message: "Parse error"} + } + c.data = &types.StringC{ + Value: parts[2], + Comment: comment, + } + return "", nil +} + +func (c *CompressionDirection) Result() ([]common.ReturnResultLine, error) { + if c.data == nil { + return nil, errors.ErrFetch + } + return []common.ReturnResultLine{ + { + Data: fmt.Sprintf("compression direction %s", c.data.Value), + Comment: c.data.Comment, + }, + }, nil +} diff --git a/config-parser/parsers/compression-direction_generated.go b/config-parser/parsers/compression-direction_generated.go new file mode 100644 index 00000000..2b014e55 --- /dev/null +++ b/config-parser/parsers/compression-direction_generated.go @@ -0,0 +1,99 @@ +// Code generated by go generate; DO NOT EDIT. +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package parsers + +import ( + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +func (p *CompressionDirection) Init() { + p.data = nil + p.preComments = []string{} +} + +func (p *CompressionDirection) GetParserName() string { + return "compression direction" +} + +func (p *CompressionDirection) Get(createIfNotExist bool) (common.ParserData, error) { + if p.data == nil { + if createIfNotExist { + p.data = &types.StringC{} + return p.data, nil + } + return nil, errors.ErrFetch + } + return p.data, nil +} + +func (p *CompressionDirection) GetPreComments() ([]string, error) { + return p.preComments, nil +} + +func (p *CompressionDirection) SetPreComments(preComments []string) { + p.preComments = preComments +} + +func (p *CompressionDirection) GetOne(index int) (common.ParserData, error) { + if index > 0 { + return nil, errors.ErrFetch + } + if p.data == nil { + return nil, errors.ErrFetch + } + return p.data, nil +} + +func (p *CompressionDirection) Delete(index int) error { + p.Init() + return nil +} + +func (p *CompressionDirection) Insert(data common.ParserData, index int) error { + return p.Set(data, index) +} + +func (p *CompressionDirection) Set(data common.ParserData, index int) error { + if data == nil { + p.Init() + return nil + } + switch newValue := data.(type) { + case *types.StringC: + p.data = newValue + case types.StringC: + p.data = &newValue + default: + return errors.ErrInvalidData + } + return nil +} + +func (p *CompressionDirection) PreParse(line string, parts []string, preComments []string, comment string) (string, error) { + changeState, err := p.Parse(line, parts, comment) + if err == nil && preComments != nil { + p.preComments = append(p.preComments, preComments...) + } + return changeState, err +} + +func (p *CompressionDirection) ResultAll() ([]common.ReturnResultLine, []string, error) { + res, err := p.Result() + return res, p.preComments, err +} diff --git a/config-parser/parsers/compression-offload.go b/config-parser/parsers/compression-offload.go new file mode 100644 index 00000000..8032dd97 --- /dev/null +++ b/config-parser/parsers/compression-offload.go @@ -0,0 +1,50 @@ +/* +Copyright 2022 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package parsers + +import ( + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +type CompressionOffload struct { + data *types.Enabled + preComments []string // comments that appear before the actual line +} + +func (c *CompressionOffload) Parse(line string, parts []string, comment string) (string, error) { + if len(parts) == 2 && parts[0] == "compression" && parts[1] == "offload" { + c.data = &types.Enabled{ + Comment: comment, + } + return "", nil + } + return "", &errors.ParseError{Parser: "CompressionOffload", Line: line, Message: "Parse error"} +} + +func (c *CompressionOffload) Result() ([]common.ReturnResultLine, error) { + if c.data == nil { + return nil, errors.ErrFetch + } + return []common.ReturnResultLine{ + { + Data: "compression offload", + Comment: c.data.Comment, + }, + }, nil +} diff --git a/config-parser/parsers/compression-offload_generated.go b/config-parser/parsers/compression-offload_generated.go new file mode 100644 index 00000000..99aec8bc --- /dev/null +++ b/config-parser/parsers/compression-offload_generated.go @@ -0,0 +1,99 @@ +// Code generated by go generate; DO NOT EDIT. +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package parsers + +import ( + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +func (p *CompressionOffload) Init() { + p.data = nil + p.preComments = []string{} +} + +func (p *CompressionOffload) GetParserName() string { + return "compression offload" +} + +func (p *CompressionOffload) Get(createIfNotExist bool) (common.ParserData, error) { + if p.data == nil { + if createIfNotExist { + p.data = &types.Enabled{} + return p.data, nil + } + return nil, errors.ErrFetch + } + return p.data, nil +} + +func (p *CompressionOffload) GetPreComments() ([]string, error) { + return p.preComments, nil +} + +func (p *CompressionOffload) SetPreComments(preComments []string) { + p.preComments = preComments +} + +func (p *CompressionOffload) GetOne(index int) (common.ParserData, error) { + if index > 0 { + return nil, errors.ErrFetch + } + if p.data == nil { + return nil, errors.ErrFetch + } + return p.data, nil +} + +func (p *CompressionOffload) Delete(index int) error { + p.Init() + return nil +} + +func (p *CompressionOffload) Insert(data common.ParserData, index int) error { + return p.Set(data, index) +} + +func (p *CompressionOffload) Set(data common.ParserData, index int) error { + if data == nil { + p.Init() + return nil + } + switch newValue := data.(type) { + case *types.Enabled: + p.data = newValue + case types.Enabled: + p.data = &newValue + default: + return errors.ErrInvalidData + } + return nil +} + +func (p *CompressionOffload) PreParse(line string, parts []string, preComments []string, comment string) (string, error) { + changeState, err := p.Parse(line, parts, comment) + if err == nil && preComments != nil { + p.preComments = append(p.preComments, preComments...) + } + return changeState, err +} + +func (p *CompressionOffload) ResultAll() ([]common.ReturnResultLine, []string, error) { + res, err := p.Result() + return res, p.preComments, err +} diff --git a/config-parser/parsers/compression-type-req.go b/config-parser/parsers/compression-type-req.go new file mode 100644 index 00000000..e1838ef9 --- /dev/null +++ b/config-parser/parsers/compression-type-req.go @@ -0,0 +1,61 @@ +/* +Copyright 2022 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package parsers + +import ( + "strings" + + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +type CompressionTypeReq struct { + data *types.StringSliceC + preComments []string // comments that appear before the actual line +} + +func (c *CompressionTypeReq) Parse(line string, parts []string, comment string) (string, error) { + if len(parts) < 3 { + return "", &errors.ParseError{Parser: "CompressionTypeReq", Line: line, Message: "Parse error"} + } + c.data = &types.StringSliceC{ + Value: parts[2:], + Comment: comment, + } + return "", nil +} + +func (c *CompressionTypeReq) Result() ([]common.ReturnResultLine, error) { + if c.data == nil || len(c.data.Value) == 0 { + return nil, errors.ErrFetch + } + var result strings.Builder + result.WriteString("compression type-req") + + for _, typereq := range c.data.Value { + result.WriteString(" ") + result.WriteString(typereq) + } + + return []common.ReturnResultLine{ + { + Data: result.String(), + Comment: c.data.Comment, + }, + }, nil +} diff --git a/config-parser/parsers/compression-type-req_generated.go b/config-parser/parsers/compression-type-req_generated.go new file mode 100644 index 00000000..bc857d83 --- /dev/null +++ b/config-parser/parsers/compression-type-req_generated.go @@ -0,0 +1,99 @@ +// Code generated by go generate; DO NOT EDIT. +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package parsers + +import ( + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +func (p *CompressionTypeReq) Init() { + p.data = nil + p.preComments = []string{} +} + +func (p *CompressionTypeReq) GetParserName() string { + return "compression type-req" +} + +func (p *CompressionTypeReq) Get(createIfNotExist bool) (common.ParserData, error) { + if p.data == nil { + if createIfNotExist { + p.data = &types.StringSliceC{} + return p.data, nil + } + return nil, errors.ErrFetch + } + return p.data, nil +} + +func (p *CompressionTypeReq) GetPreComments() ([]string, error) { + return p.preComments, nil +} + +func (p *CompressionTypeReq) SetPreComments(preComments []string) { + p.preComments = preComments +} + +func (p *CompressionTypeReq) GetOne(index int) (common.ParserData, error) { + if index > 0 { + return nil, errors.ErrFetch + } + if p.data == nil { + return nil, errors.ErrFetch + } + return p.data, nil +} + +func (p *CompressionTypeReq) Delete(index int) error { + p.Init() + return nil +} + +func (p *CompressionTypeReq) Insert(data common.ParserData, index int) error { + return p.Set(data, index) +} + +func (p *CompressionTypeReq) Set(data common.ParserData, index int) error { + if data == nil { + p.Init() + return nil + } + switch newValue := data.(type) { + case *types.StringSliceC: + p.data = newValue + case types.StringSliceC: + p.data = &newValue + default: + return errors.ErrInvalidData + } + return nil +} + +func (p *CompressionTypeReq) PreParse(line string, parts []string, preComments []string, comment string) (string, error) { + changeState, err := p.Parse(line, parts, comment) + if err == nil && preComments != nil { + p.preComments = append(p.preComments, preComments...) + } + return changeState, err +} + +func (p *CompressionTypeReq) ResultAll() ([]common.ReturnResultLine, []string, error) { + res, err := p.Result() + return res, p.preComments, err +} diff --git a/config-parser/parsers/compression-type-res.go b/config-parser/parsers/compression-type-res.go new file mode 100644 index 00000000..251b5fad --- /dev/null +++ b/config-parser/parsers/compression-type-res.go @@ -0,0 +1,61 @@ +/* +Copyright 2022 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package parsers + +import ( + "strings" + + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +type CompressionTypeRes struct { + data *types.StringSliceC + preComments []string // comments that appear before the actual line +} + +func (c *CompressionTypeRes) Parse(line string, parts []string, comment string) (string, error) { + if len(parts) < 3 { + return "", &errors.ParseError{Parser: "CompressionTypeRes", Line: line, Message: "Parse error"} + } + c.data = &types.StringSliceC{ + Value: parts[2:], + Comment: comment, + } + return "", nil +} + +func (c *CompressionTypeRes) Result() ([]common.ReturnResultLine, error) { + if c.data == nil || len(c.data.Value) == 0 { + return nil, errors.ErrFetch + } + var result strings.Builder + result.WriteString("compression type-res") + + for _, typereq := range c.data.Value { + result.WriteString(" ") + result.WriteString(typereq) + } + + return []common.ReturnResultLine{ + { + Data: result.String(), + Comment: c.data.Comment, + }, + }, nil +} diff --git a/config-parser/parsers/compression-type-res_generated.go b/config-parser/parsers/compression-type-res_generated.go new file mode 100644 index 00000000..a46e5a1f --- /dev/null +++ b/config-parser/parsers/compression-type-res_generated.go @@ -0,0 +1,99 @@ +// Code generated by go generate; DO NOT EDIT. +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package parsers + +import ( + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +func (p *CompressionTypeRes) Init() { + p.data = nil + p.preComments = []string{} +} + +func (p *CompressionTypeRes) GetParserName() string { + return "compression type-res" +} + +func (p *CompressionTypeRes) Get(createIfNotExist bool) (common.ParserData, error) { + if p.data == nil { + if createIfNotExist { + p.data = &types.StringSliceC{} + return p.data, nil + } + return nil, errors.ErrFetch + } + return p.data, nil +} + +func (p *CompressionTypeRes) GetPreComments() ([]string, error) { + return p.preComments, nil +} + +func (p *CompressionTypeRes) SetPreComments(preComments []string) { + p.preComments = preComments +} + +func (p *CompressionTypeRes) GetOne(index int) (common.ParserData, error) { + if index > 0 { + return nil, errors.ErrFetch + } + if p.data == nil { + return nil, errors.ErrFetch + } + return p.data, nil +} + +func (p *CompressionTypeRes) Delete(index int) error { + p.Init() + return nil +} + +func (p *CompressionTypeRes) Insert(data common.ParserData, index int) error { + return p.Set(data, index) +} + +func (p *CompressionTypeRes) Set(data common.ParserData, index int) error { + if data == nil { + p.Init() + return nil + } + switch newValue := data.(type) { + case *types.StringSliceC: + p.data = newValue + case types.StringSliceC: + p.data = &newValue + default: + return errors.ErrInvalidData + } + return nil +} + +func (p *CompressionTypeRes) PreParse(line string, parts []string, preComments []string, comment string) (string, error) { + changeState, err := p.Parse(line, parts, comment) + if err == nil && preComments != nil { + p.preComments = append(p.preComments, preComments...) + } + return changeState, err +} + +func (p *CompressionTypeRes) ResultAll() ([]common.ReturnResultLine, []string, error) { + res, err := p.Result() + return res, p.preComments, err +} diff --git a/config-parser/parsers/compression-type.go b/config-parser/parsers/compression-type.go new file mode 100644 index 00000000..7aeb1973 --- /dev/null +++ b/config-parser/parsers/compression-type.go @@ -0,0 +1,61 @@ +/* +Copyright 2022 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package parsers + +import ( + "strings" + + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +type CompressionType struct { + data *types.StringSliceC + preComments []string // comments that appear before the actual line +} + +func (c *CompressionType) Parse(line string, parts []string, comment string) (string, error) { + if len(parts) < 3 { + return "", &errors.ParseError{Parser: "CompressionType", Line: line, Message: "Parse error"} + } + c.data = &types.StringSliceC{ + Value: parts[2:], + Comment: comment, + } + return "", nil +} + +func (c *CompressionType) Result() ([]common.ReturnResultLine, error) { + if c.data == nil || len(c.data.Value) == 0 { + return nil, errors.ErrFetch + } + var result strings.Builder + result.WriteString("compression type") + + for _, algo := range c.data.Value { + result.WriteString(" ") + result.WriteString(algo) + } + + return []common.ReturnResultLine{ + { + Data: result.String(), + Comment: c.data.Comment, + }, + }, nil +} diff --git a/config-parser/parsers/compression-type_generated.go b/config-parser/parsers/compression-type_generated.go new file mode 100644 index 00000000..ea252eac --- /dev/null +++ b/config-parser/parsers/compression-type_generated.go @@ -0,0 +1,99 @@ +// Code generated by go generate; DO NOT EDIT. +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package parsers + +import ( + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +func (p *CompressionType) Init() { + p.data = nil + p.preComments = []string{} +} + +func (p *CompressionType) GetParserName() string { + return "compression type" +} + +func (p *CompressionType) Get(createIfNotExist bool) (common.ParserData, error) { + if p.data == nil { + if createIfNotExist { + p.data = &types.StringSliceC{} + return p.data, nil + } + return nil, errors.ErrFetch + } + return p.data, nil +} + +func (p *CompressionType) GetPreComments() ([]string, error) { + return p.preComments, nil +} + +func (p *CompressionType) SetPreComments(preComments []string) { + p.preComments = preComments +} + +func (p *CompressionType) GetOne(index int) (common.ParserData, error) { + if index > 0 { + return nil, errors.ErrFetch + } + if p.data == nil { + return nil, errors.ErrFetch + } + return p.data, nil +} + +func (p *CompressionType) Delete(index int) error { + p.Init() + return nil +} + +func (p *CompressionType) Insert(data common.ParserData, index int) error { + return p.Set(data, index) +} + +func (p *CompressionType) Set(data common.ParserData, index int) error { + if data == nil { + p.Init() + return nil + } + switch newValue := data.(type) { + case *types.StringSliceC: + p.data = newValue + case types.StringSliceC: + p.data = &newValue + default: + return errors.ErrInvalidData + } + return nil +} + +func (p *CompressionType) PreParse(line string, parts []string, preComments []string, comment string) (string, error) { + changeState, err := p.Parse(line, parts, comment) + if err == nil && preComments != nil { + p.preComments = append(p.preComments, preComments...) + } + return changeState, err +} + +func (p *CompressionType) ResultAll() ([]common.ReturnResultLine, []string, error) { + res, err := p.Result() + return res, p.preComments, err +} diff --git a/config-parser/parsers/config-snippet.go b/config-parser/parsers/config-snippet.go new file mode 100644 index 00000000..3cffdd4e --- /dev/null +++ b/config-parser/parsers/config-snippet.go @@ -0,0 +1,68 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package parsers + +import ( + "strings" + + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +type ConfigSnippet struct { + data *types.StringSliceC + active bool + preComments []string // comments that appear before the actual line +} + +func (p *ConfigSnippet) Parse(line string, parts []string, comment string) (string, error) { + if comment != "" { + commentParts := strings.Fields(comment) + if len(commentParts) > 1 || commentParts[0] == "##_config-snippet_###" { + switch commentParts[1] { + case "BEGIN": + p.active = true + p.data = &types.StringSliceC{} + return "snippet_beg", nil + case "END": + p.active = false + return "snippet_end", nil + default: + p.data.Value = append(p.data.Value, strings.TrimSpace(line)) + return "", nil + } + } + } + if p.active { + p.data.Value = append(p.data.Value, strings.TrimSpace(line)) + return "", nil + } + return "", &errors.ParseError{Parser: "ConfigSnippet", Line: line} +} + +func (p *ConfigSnippet) Result() ([]common.ReturnResultLine, error) { + if p.data == nil { + return nil, errors.ErrFetch + } + return []common.ReturnResultLine{ + { + Data: "###_config-snippet_### BEGIN\n " + strings.Join(p.data.Value, "\n ") + "\n ###_config-snippet_### END", + Comment: p.data.Comment, + }, + }, nil +} diff --git a/config-parser/parsers/config-snippet_generated.go b/config-parser/parsers/config-snippet_generated.go new file mode 100644 index 00000000..f64ba6cc --- /dev/null +++ b/config-parser/parsers/config-snippet_generated.go @@ -0,0 +1,99 @@ +// Code generated by go generate; DO NOT EDIT. +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package parsers + +import ( + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +func (p *ConfigSnippet) Init() { + p.data = nil + p.preComments = []string{} +} + +func (p *ConfigSnippet) GetParserName() string { + return "config-snippet" +} + +func (p *ConfigSnippet) Get(createIfNotExist bool) (common.ParserData, error) { + if p.data == nil { + if createIfNotExist { + p.data = &types.StringSliceC{} + return p.data, nil + } + return nil, errors.ErrFetch + } + return p.data, nil +} + +func (p *ConfigSnippet) GetPreComments() ([]string, error) { + return p.preComments, nil +} + +func (p *ConfigSnippet) SetPreComments(preComments []string) { + p.preComments = preComments +} + +func (p *ConfigSnippet) GetOne(index int) (common.ParserData, error) { + if index > 0 { + return nil, errors.ErrFetch + } + if p.data == nil { + return nil, errors.ErrFetch + } + return p.data, nil +} + +func (p *ConfigSnippet) Delete(index int) error { + p.Init() + return nil +} + +func (p *ConfigSnippet) Insert(data common.ParserData, index int) error { + return p.Set(data, index) +} + +func (p *ConfigSnippet) Set(data common.ParserData, index int) error { + if data == nil { + p.Init() + return nil + } + switch newValue := data.(type) { + case *types.StringSliceC: + p.data = newValue + case types.StringSliceC: + p.data = &newValue + default: + return errors.ErrInvalidData + } + return nil +} + +func (p *ConfigSnippet) PreParse(line string, parts []string, preComments []string, comment string) (string, error) { + changeState, err := p.Parse(line, parts, comment) + if err == nil && preComments != nil { + p.preComments = append(p.preComments, preComments...) + } + return changeState, err +} + +func (p *ConfigSnippet) ResultAll() ([]common.ReturnResultLine, []string, error) { + res, err := p.Result() + return res, p.preComments, err +} diff --git a/config-parser/parsers/cookie.go b/config-parser/parsers/cookie.go new file mode 100644 index 00000000..46f792dc --- /dev/null +++ b/config-parser/parsers/cookie.go @@ -0,0 +1,168 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package parsers + +import ( + "strconv" + "strings" + + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +const CookieKeyword = "cookie" + +type Cookie struct { + data *types.Cookie + preComments []string // comments that appear before the actual line +} + +func (p *Cookie) Parse(line string, parts []string, comment string) (string, error) { //nolint:gocognit + var err error + if parts[0] == CookieKeyword { + if len(parts) < 2 { + return "", &errors.ParseError{Parser: "Cookie", Line: line, Message: "Parse error"} + } + data := &types.Cookie{ + Domain: []string{}, + Attr: []string{}, + Name: parts[1], + Comment: comment, + } + + for i := 2; i < len(parts); i++ { + el := parts[i] + switch el { + case "insert", "rewrite", "prefix": + data.Type = el + case "dynamic": + data.Dynamic = true + case "httponly": + data.Httponly = true + case "indirect": + data.Indirect = true + case "nocache": + data.Nocache = true + case "postonly": + data.Postonly = true + case "preserve": + data.Preserve = true + case "secure": + data.Secure = true + case "domain": + if (i + 1) < len(parts) { + i++ + data.Domain = append(data.Domain, parts[i]) + } + case "attr": + if (i + 1) < len(parts) { + i++ + if strings.ContainsAny(parts[i], "\x00\a\b\t\n\v\f\r;") { + return "", &errors.ParseError{Parser: "attr", Line: line, Message: "cookie attr contained control character or semicolon"} + } + data.Attr = append(data.Attr, parts[i]) + } + case "maxidle": + if (i + 1) < len(parts) { + i++ + if data.Maxidle, err = strconv.ParseInt(parts[i], 10, 64); err != nil { + return "", &errors.ParseError{Parser: "maxidle", Line: line, Message: err.Error()} + } + } + case "maxlife": + if (i + 1) < len(parts) { + i++ + if data.Maxlife, err = strconv.ParseInt(parts[i], 10, 64); err != nil { + return "", &errors.ParseError{Parser: "maxlife", Line: line, Message: err.Error()} + } + } + } + } + + p.data = data + return "", nil + } + return "", &errors.ParseError{Parser: "Cookie", Line: line} +} + +func (p *Cookie) Result() ([]common.ReturnResultLine, error) { + if p.data == nil { + return nil, errors.ErrFetch + } + + var result strings.Builder + result.WriteString(CookieKeyword) + + if p.data.Name != "" { + result.WriteString(" ") + result.WriteString(p.data.Name) + } + + if len(p.data.Domain) > 0 { + for _, domain := range p.data.Domain { + result.WriteString(" domain ") + result.WriteString(domain) + } + } + if len(p.data.Attr) > 0 { + for _, attr := range p.data.Attr { + result.WriteString(" attr ") + result.WriteString(attr) + } + } + if p.data.Dynamic { + result.WriteString(" dynamic") + } + if p.data.Httponly { + result.WriteString(" httponly") + } + if p.data.Indirect { + result.WriteString(" indirect") + } + if p.data.Maxidle > 0 { + result.WriteString(" maxidle ") + result.WriteString(strconv.Itoa(int(p.data.Maxidle))) + } + if p.data.Maxlife > 0 { + result.WriteString(" maxlife ") + result.WriteString(strconv.Itoa(int(p.data.Maxlife))) + } + if p.data.Nocache { + result.WriteString(" nocache") + } + if p.data.Postonly { + result.WriteString(" postonly") + } + if p.data.Preserve { + result.WriteString(" preserve") + } + if p.data.Type != "" { + result.WriteString(" ") + result.WriteString(p.data.Type) + } + if p.data.Secure { + result.WriteString(" secure") + } + + return []common.ReturnResultLine{ + { + Data: result.String(), + Comment: p.data.Comment, + }, + }, nil +} diff --git a/config-parser/parsers/cookie_generated.go b/config-parser/parsers/cookie_generated.go new file mode 100644 index 00000000..05ca5fee --- /dev/null +++ b/config-parser/parsers/cookie_generated.go @@ -0,0 +1,99 @@ +// Code generated by go generate; DO NOT EDIT. +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package parsers + +import ( + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +func (p *Cookie) Init() { + p.data = nil + p.preComments = []string{} +} + +func (p *Cookie) GetParserName() string { + return "cookie" +} + +func (p *Cookie) Get(createIfNotExist bool) (common.ParserData, error) { + if p.data == nil { + if createIfNotExist { + p.data = &types.Cookie{} + return p.data, nil + } + return nil, errors.ErrFetch + } + return p.data, nil +} + +func (p *Cookie) GetPreComments() ([]string, error) { + return p.preComments, nil +} + +func (p *Cookie) SetPreComments(preComments []string) { + p.preComments = preComments +} + +func (p *Cookie) GetOne(index int) (common.ParserData, error) { + if index > 0 { + return nil, errors.ErrFetch + } + if p.data == nil { + return nil, errors.ErrFetch + } + return p.data, nil +} + +func (p *Cookie) Delete(index int) error { + p.Init() + return nil +} + +func (p *Cookie) Insert(data common.ParserData, index int) error { + return p.Set(data, index) +} + +func (p *Cookie) Set(data common.ParserData, index int) error { + if data == nil { + p.Init() + return nil + } + switch newValue := data.(type) { + case *types.Cookie: + p.data = newValue + case types.Cookie: + p.data = &newValue + default: + return errors.ErrInvalidData + } + return nil +} + +func (p *Cookie) PreParse(line string, parts []string, preComments []string, comment string) (string, error) { + changeState, err := p.Parse(line, parts, comment) + if err == nil && preComments != nil { + p.preComments = append(p.preComments, preComments...) + } + return changeState, err +} + +func (p *Cookie) ResultAll() ([]common.ReturnResultLine, []string, error) { + res, err := p.Result() + return res, p.preComments, err +} diff --git a/config-parser/parsers/cpu-map.go b/config-parser/parsers/cpu-map.go new file mode 100644 index 00000000..e4b37dda --- /dev/null +++ b/config-parser/parsers/cpu-map.go @@ -0,0 +1,85 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package parsers + +import ( + "fmt" + "strings" + + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +type CPUMap struct { + data []types.CPUMap + preComments []string // comments that appear before the actual line +} + +func (c *CPUMap) parse(line string, parts []string, comment string) (*types.CPUMap, error) { + if len(parts) < 3 { + return nil, &errors.ParseError{Parser: "CPUMap", Line: line, Message: "Parse error"} + } + cpuMap := &types.CPUMap{ + Process: parts[1], + CPUSet: strings.Join(parts[2:], " "), + Comment: comment, + } + return cpuMap, nil +} + +func (c *CPUMap) Result() ([]common.ReturnResultLine, error) { + if len(c.data) == 0 { + return nil, errors.ErrFetch + } + result := make([]common.ReturnResultLine, len(c.data)) + for index, cpuMap := range c.data { + result[index] = common.ReturnResultLine{ + Data: fmt.Sprintf("cpu-map %s %s", cpuMap.Process, cpuMap.CPUSet), + Comment: cpuMap.Comment, + } + } + return result, nil +} + +func (c *CPUMap) Equal(b *CPUMap) bool { + if b == nil { + return false + } + if b.data == nil { + return false + } + if len(c.data) != len(b.data) { + return false + } + for _, cCPUMap := range c.data { + found := false + for _, bCPUMap := range b.data { + if cCPUMap.Process == bCPUMap.Process { + if cCPUMap.CPUSet != bCPUMap.CPUSet { + return false + } + found = true + break + } + } + if !found { + return false + } + } + return true +} diff --git a/config-parser/parsers/cpu-map_generated.go b/config-parser/parsers/cpu-map_generated.go new file mode 100644 index 00000000..00bc3518 --- /dev/null +++ b/config-parser/parsers/cpu-map_generated.go @@ -0,0 +1,157 @@ +// Code generated by go generate; DO NOT EDIT. +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package parsers + +import ( + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +func (p *CPUMap) Init() { + p.data = []types.CPUMap{} + p.preComments = []string{} +} + +func (p *CPUMap) GetParserName() string { + return "cpu-map" +} + +func (p *CPUMap) Get(createIfNotExist bool) (common.ParserData, error) { + if len(p.data) == 0 && !createIfNotExist { + return nil, errors.ErrFetch + } + return p.data, nil +} + +func (p *CPUMap) GetPreComments() ([]string, error) { + return p.preComments, nil +} + +func (p *CPUMap) SetPreComments(preComments []string) { + p.preComments = preComments +} + +func (p *CPUMap) GetOne(index int) (common.ParserData, error) { + if index < 0 || index >= len(p.data) { + return nil, errors.ErrFetch + } + return p.data[index], nil +} + +func (p *CPUMap) Delete(index int) error { + if index < 0 || index >= len(p.data) { + return errors.ErrFetch + } + copy(p.data[index:], p.data[index+1:]) + p.data[len(p.data)-1] = types.CPUMap{} + p.data = p.data[:len(p.data)-1] + return nil +} + +func (p *CPUMap) Insert(data common.ParserData, index int) error { + if data == nil { + return errors.ErrInvalidData + } + switch newValue := data.(type) { + case []types.CPUMap: + p.data = newValue + case *types.CPUMap: + if index > -1 { + if index > len(p.data) { + return errors.ErrIndexOutOfRange + } + p.data = append(p.data, types.CPUMap{}) + copy(p.data[index+1:], p.data[index:]) + p.data[index] = *newValue + } else { + p.data = append(p.data, *newValue) + } + case types.CPUMap: + if index > -1 { + if index > len(p.data) { + return errors.ErrIndexOutOfRange + } + p.data = append(p.data, types.CPUMap{}) + copy(p.data[index+1:], p.data[index:]) + p.data[index] = newValue + } else { + p.data = append(p.data, newValue) + } + default: + return errors.ErrInvalidData + } + return nil +} + +func (p *CPUMap) Set(data common.ParserData, index int) error { + if data == nil { + p.Init() + return nil + } + switch newValue := data.(type) { + case []types.CPUMap: + p.data = newValue + case *types.CPUMap: + if index > -1 && index < len(p.data) { + p.data[index] = *newValue + } else if index == -1 { + p.data = append(p.data, *newValue) + } else { + return errors.ErrIndexOutOfRange + } + case types.CPUMap: + if index > -1 && index < len(p.data) { + p.data[index] = newValue + } else if index == -1 { + p.data = append(p.data, newValue) + } else { + return errors.ErrIndexOutOfRange + } + default: + return errors.ErrInvalidData + } + return nil +} + +func (p *CPUMap) PreParse(line string, parts []string, preComments []string, comment string) (string, error) { + changeState, err := p.Parse(line, parts, comment) + if err == nil && preComments != nil { + p.preComments = append(p.preComments, preComments...) + } + return changeState, err +} + +func (p *CPUMap) Parse(line string, parts []string, comment string) (string, error) { + if parts[0] == "cpu-map" { + data, err := p.parse(line, parts, comment) + if err != nil { + if _, ok := err.(*errors.ParseError); ok { + return "", err + } + return "", &errors.ParseError{Parser: "CPUMap", Line: line} + } + p.data = append(p.data, *data) + return "", nil + } + return "", &errors.ParseError{Parser: "CPUMap", Line: line} +} + +func (p *CPUMap) ResultAll() ([]common.ReturnResultLine, []string, error) { + res, err := p.Result() + return res, p.preComments, err +} diff --git a/config-parser/parsers/daemon.go b/config-parser/parsers/daemon.go new file mode 100644 index 00000000..096d1a92 --- /dev/null +++ b/config-parser/parsers/daemon.go @@ -0,0 +1,50 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package parsers + +import ( + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +type Daemon struct { + data *types.Enabled + preComments []string // comments that appear before the actual line +} + +func (d *Daemon) Parse(line string, parts []string, comment string) (string, error) { + if parts[0] == "daemon" { + d.data = &types.Enabled{ + Comment: comment, + } + return "", nil + } + return "", &errors.ParseError{Parser: "Daemon", Line: line} +} + +func (d *Daemon) Result() ([]common.ReturnResultLine, error) { + if d.data == nil { + return nil, errors.ErrFetch + } + return []common.ReturnResultLine{ + { + Data: "daemon", + Comment: d.data.Comment, + }, + }, nil +} diff --git a/config-parser/parsers/daemon_generated.go b/config-parser/parsers/daemon_generated.go new file mode 100644 index 00000000..ec21d78d --- /dev/null +++ b/config-parser/parsers/daemon_generated.go @@ -0,0 +1,99 @@ +// Code generated by go generate; DO NOT EDIT. +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package parsers + +import ( + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +func (p *Daemon) Init() { + p.data = nil + p.preComments = []string{} +} + +func (p *Daemon) GetParserName() string { + return "daemon" +} + +func (p *Daemon) Get(createIfNotExist bool) (common.ParserData, error) { + if p.data == nil { + if createIfNotExist { + p.data = &types.Enabled{} + return p.data, nil + } + return nil, errors.ErrFetch + } + return p.data, nil +} + +func (p *Daemon) GetPreComments() ([]string, error) { + return p.preComments, nil +} + +func (p *Daemon) SetPreComments(preComments []string) { + p.preComments = preComments +} + +func (p *Daemon) GetOne(index int) (common.ParserData, error) { + if index > 0 { + return nil, errors.ErrFetch + } + if p.data == nil { + return nil, errors.ErrFetch + } + return p.data, nil +} + +func (p *Daemon) Delete(index int) error { + p.Init() + return nil +} + +func (p *Daemon) Insert(data common.ParserData, index int) error { + return p.Set(data, index) +} + +func (p *Daemon) Set(data common.ParserData, index int) error { + if data == nil { + p.Init() + return nil + } + switch newValue := data.(type) { + case *types.Enabled: + p.data = newValue + case types.Enabled: + p.data = &newValue + default: + return errors.ErrInvalidData + } + return nil +} + +func (p *Daemon) PreParse(line string, parts []string, preComments []string, comment string) (string, error) { + changeState, err := p.Parse(line, parts, comment) + if err == nil && preComments != nil { + p.preComments = append(p.preComments, preComments...) + } + return changeState, err +} + +func (p *Daemon) ResultAll() ([]common.ReturnResultLine, []string, error) { + res, err := p.Result() + return res, p.preComments, err +} diff --git a/config-parser/parsers/declare-capture.go b/config-parser/parsers/declare-capture.go new file mode 100644 index 00000000..502f3353 --- /dev/null +++ b/config-parser/parsers/declare-capture.go @@ -0,0 +1,66 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package parsers + +import ( + "fmt" + "strconv" + + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +type DeclareCapture struct { + data []types.DeclareCapture + preComments []string // comments that appear before the actual line +} + +func (dc *DeclareCapture) parse(line string, parts []string, comment string) (*types.DeclareCapture, error) { + if len(parts) != 5 { + return nil, &errors.ParseError{Parser: "DeclareCapture", Line: line, Message: "Parse error"} + } + + if parts[3] != "len" { + return nil, &errors.ParseError{Parser: "DeclareCapture", Line: line, Message: "Parse error"} + } + + length, err := strconv.ParseInt(parts[4], 10, 64) + if err != nil { + return nil, &errors.ParseError{Parser: "DeclareCapture", Line: line, Message: "Parse error"} + } + declareCapture := &types.DeclareCapture{ + Type: parts[2], + Length: length, + Comment: comment, + } + return declareCapture, nil +} + +func (dc *DeclareCapture) Result() ([]common.ReturnResultLine, error) { + if len(dc.data) == 0 { + return nil, errors.ErrFetch + } + result := make([]common.ReturnResultLine, len(dc.data)) + for index, declareCapture := range dc.data { + result[index] = common.ReturnResultLine{ + Data: fmt.Sprintf("declare capture %s len %d", declareCapture.Type, declareCapture.Length), + Comment: declareCapture.Comment, + } + } + return result, nil +} diff --git a/config-parser/parsers/declare-capture_generated.go b/config-parser/parsers/declare-capture_generated.go new file mode 100644 index 00000000..2efbdba5 --- /dev/null +++ b/config-parser/parsers/declare-capture_generated.go @@ -0,0 +1,157 @@ +// Code generated by go generate; DO NOT EDIT. +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package parsers + +import ( + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +func (p *DeclareCapture) Init() { + p.data = []types.DeclareCapture{} + p.preComments = []string{} +} + +func (p *DeclareCapture) GetParserName() string { + return "declare capture" +} + +func (p *DeclareCapture) Get(createIfNotExist bool) (common.ParserData, error) { + if len(p.data) == 0 && !createIfNotExist { + return nil, errors.ErrFetch + } + return p.data, nil +} + +func (p *DeclareCapture) GetPreComments() ([]string, error) { + return p.preComments, nil +} + +func (p *DeclareCapture) SetPreComments(preComments []string) { + p.preComments = preComments +} + +func (p *DeclareCapture) GetOne(index int) (common.ParserData, error) { + if index < 0 || index >= len(p.data) { + return nil, errors.ErrFetch + } + return p.data[index], nil +} + +func (p *DeclareCapture) Delete(index int) error { + if index < 0 || index >= len(p.data) { + return errors.ErrFetch + } + copy(p.data[index:], p.data[index+1:]) + p.data[len(p.data)-1] = types.DeclareCapture{} + p.data = p.data[:len(p.data)-1] + return nil +} + +func (p *DeclareCapture) Insert(data common.ParserData, index int) error { + if data == nil { + return errors.ErrInvalidData + } + switch newValue := data.(type) { + case []types.DeclareCapture: + p.data = newValue + case *types.DeclareCapture: + if index > -1 { + if index > len(p.data) { + return errors.ErrIndexOutOfRange + } + p.data = append(p.data, types.DeclareCapture{}) + copy(p.data[index+1:], p.data[index:]) + p.data[index] = *newValue + } else { + p.data = append(p.data, *newValue) + } + case types.DeclareCapture: + if index > -1 { + if index > len(p.data) { + return errors.ErrIndexOutOfRange + } + p.data = append(p.data, types.DeclareCapture{}) + copy(p.data[index+1:], p.data[index:]) + p.data[index] = newValue + } else { + p.data = append(p.data, newValue) + } + default: + return errors.ErrInvalidData + } + return nil +} + +func (p *DeclareCapture) Set(data common.ParserData, index int) error { + if data == nil { + p.Init() + return nil + } + switch newValue := data.(type) { + case []types.DeclareCapture: + p.data = newValue + case *types.DeclareCapture: + if index > -1 && index < len(p.data) { + p.data[index] = *newValue + } else if index == -1 { + p.data = append(p.data, *newValue) + } else { + return errors.ErrIndexOutOfRange + } + case types.DeclareCapture: + if index > -1 && index < len(p.data) { + p.data[index] = newValue + } else if index == -1 { + p.data = append(p.data, newValue) + } else { + return errors.ErrIndexOutOfRange + } + default: + return errors.ErrInvalidData + } + return nil +} + +func (p *DeclareCapture) PreParse(line string, parts []string, preComments []string, comment string) (string, error) { + changeState, err := p.Parse(line, parts, comment) + if err == nil && preComments != nil { + p.preComments = append(p.preComments, preComments...) + } + return changeState, err +} + +func (p *DeclareCapture) Parse(line string, parts []string, comment string) (string, error) { + if len(parts) > 1 && parts[0] == "declare" && parts[1] == "capture" { + data, err := p.parse(line, parts, comment) + if err != nil { + if _, ok := err.(*errors.ParseError); ok { + return "", err + } + return "", &errors.ParseError{Parser: "DeclareCapture", Line: line} + } + p.data = append(p.data, *data) + return "", nil + } + return "", &errors.ParseError{Parser: "DeclareCapture", Line: line} +} + +func (p *DeclareCapture) ResultAll() ([]common.ReturnResultLine, []string, error) { + res, err := p.Result() + return res, p.preComments, err +} diff --git a/config-parser/parsers/default-backend.go b/config-parser/parsers/default-backend.go new file mode 100644 index 00000000..45ca06da --- /dev/null +++ b/config-parser/parsers/default-backend.go @@ -0,0 +1,56 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package parsers + +import ( + "fmt" + + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +type DefaultBackend struct { + data *types.StringC + preComments []string // comments that appear before the actual line +} + +func (s *DefaultBackend) Parse(line string, parts []string, comment string) (string, error) { + if parts[0] == "default_backend" { + if len(parts) < 2 { + return "", &errors.ParseError{Parser: "DefaultBackend", Line: line, Message: "Parse error"} + } + s.data = &types.StringC{ + Comment: comment, + Value: parts[1], + } + return "", nil + } + return "", &errors.ParseError{Parser: "default_backend", Line: line} +} + +func (s *DefaultBackend) Result() ([]common.ReturnResultLine, error) { + if s.data == nil { + return nil, errors.ErrFetch + } + return []common.ReturnResultLine{ + { + Data: fmt.Sprintf("default_backend %s", s.data.Value), + Comment: s.data.Comment, + }, + }, nil +} diff --git a/config-parser/parsers/default-bind.go b/config-parser/parsers/default-bind.go new file mode 100644 index 00000000..2b152899 --- /dev/null +++ b/config-parser/parsers/default-bind.go @@ -0,0 +1,62 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package parsers + +import ( + "strings" + + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/params" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +type DefaultBind struct { + data *types.DefaultBind + preComments []string // comments that appear before the actual line +} + +func (d *DefaultBind) Parse(line string, parts []string, comment string) (string, error) { + if parts[0] == "default-bind" && len(parts) > 1 { + paramsBindOptions, _ := params.ParseBindOptions(parts[1:]) + d.data = &types.DefaultBind{ + Params: paramsBindOptions, + Comment: comment, + } + return "", nil + } + return "", &errors.ParseError{Parser: "DefaultBind", Line: line} +} + +func (d *DefaultBind) Result() ([]common.ReturnResultLine, error) { + if d.data == nil { + return nil, errors.ErrFetch + } + var result strings.Builder + result.WriteString("default-bind") + options := params.BindOptionsString(d.data.Params) + if options != "" { + result.WriteString(" ") + result.WriteString(options) + } + return []common.ReturnResultLine{ + { + Data: result.String(), + Comment: d.data.Comment, + }, + }, nil +} diff --git a/config-parser/parsers/default-bind_generated.go b/config-parser/parsers/default-bind_generated.go new file mode 100644 index 00000000..b8dabfd6 --- /dev/null +++ b/config-parser/parsers/default-bind_generated.go @@ -0,0 +1,99 @@ +// Code generated by go generate; DO NOT EDIT. +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package parsers + +import ( + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +func (p *DefaultBind) Init() { + p.data = nil + p.preComments = []string{} +} + +func (p *DefaultBind) GetParserName() string { + return "default-bind" +} + +func (p *DefaultBind) Get(createIfNotExist bool) (common.ParserData, error) { + if p.data == nil { + if createIfNotExist { + p.data = &types.DefaultBind{} + return p.data, nil + } + return nil, errors.ErrFetch + } + return p.data, nil +} + +func (p *DefaultBind) GetPreComments() ([]string, error) { + return p.preComments, nil +} + +func (p *DefaultBind) SetPreComments(preComments []string) { + p.preComments = preComments +} + +func (p *DefaultBind) GetOne(index int) (common.ParserData, error) { + if index > 0 { + return nil, errors.ErrFetch + } + if p.data == nil { + return nil, errors.ErrFetch + } + return p.data, nil +} + +func (p *DefaultBind) Delete(index int) error { + p.Init() + return nil +} + +func (p *DefaultBind) Insert(data common.ParserData, index int) error { + return p.Set(data, index) +} + +func (p *DefaultBind) Set(data common.ParserData, index int) error { + if data == nil { + p.Init() + return nil + } + switch newValue := data.(type) { + case *types.DefaultBind: + p.data = newValue + case types.DefaultBind: + p.data = &newValue + default: + return errors.ErrInvalidData + } + return nil +} + +func (p *DefaultBind) PreParse(line string, parts []string, preComments []string, comment string) (string, error) { + changeState, err := p.Parse(line, parts, comment) + if err == nil && preComments != nil { + p.preComments = append(p.preComments, preComments...) + } + return changeState, err +} + +func (p *DefaultBind) ResultAll() ([]common.ReturnResultLine, []string, error) { + res, err := p.Result() + return res, p.preComments, err +} diff --git a/config-parser/parsers/default-path.go b/config-parser/parsers/default-path.go new file mode 100644 index 00000000..dcc7c0b8 --- /dev/null +++ b/config-parser/parsers/default-path.go @@ -0,0 +1,70 @@ +/* +Copyright 2022 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package parsers + +import ( + "fmt" + "strings" + + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +type DefaultPath struct { + data *types.DefaultPath + preComments []string // comments that appear before the actual line +} + +/* +default-path { current | config | parent | origin } +*/ +func (d *DefaultPath) Parse(line string, parts []string, comment string) (string, error) { + if len(parts) > 1 && parts[0] == "default-path" && + (parts[1] == "current" || parts[1] == "config" || parts[1] == "parent" || parts[1] == "origin") { + data := &types.DefaultPath{ + Type: parts[1], + Comment: comment, + } + if parts[1] == "origin" { + if len(parts) != 3 { + return "", errors.ErrInvalidData + } + data.Path = parts[2] + } + d.data = data + return "", nil + } + return "", &errors.ParseError{Parser: "default-path", Line: line} +} + +func (d *DefaultPath) Result() ([]common.ReturnResultLine, error) { + if d.data == nil { + return nil, errors.ErrFetch + } + var sb strings.Builder + fmt.Fprint(&sb, "default-path ", d.data.Type) + if d.data.Type == "origin" { + fmt.Fprint(&sb, " ", d.data.Path) + } + return []common.ReturnResultLine{ + { + Data: sb.String(), + Comment: d.data.Comment, + }, + }, nil +} diff --git a/config-parser/parsers/default-path_generated.go b/config-parser/parsers/default-path_generated.go new file mode 100644 index 00000000..f60782fd --- /dev/null +++ b/config-parser/parsers/default-path_generated.go @@ -0,0 +1,99 @@ +// Code generated by go generate; DO NOT EDIT. +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package parsers + +import ( + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +func (p *DefaultPath) Init() { + p.data = nil + p.preComments = []string{} +} + +func (p *DefaultPath) GetParserName() string { + return "default-path" +} + +func (p *DefaultPath) Get(createIfNotExist bool) (common.ParserData, error) { + if p.data == nil { + if createIfNotExist { + p.data = &types.DefaultPath{} + return p.data, nil + } + return nil, errors.ErrFetch + } + return p.data, nil +} + +func (p *DefaultPath) GetPreComments() ([]string, error) { + return p.preComments, nil +} + +func (p *DefaultPath) SetPreComments(preComments []string) { + p.preComments = preComments +} + +func (p *DefaultPath) GetOne(index int) (common.ParserData, error) { + if index > 0 { + return nil, errors.ErrFetch + } + if p.data == nil { + return nil, errors.ErrFetch + } + return p.data, nil +} + +func (p *DefaultPath) Delete(index int) error { + p.Init() + return nil +} + +func (p *DefaultPath) Insert(data common.ParserData, index int) error { + return p.Set(data, index) +} + +func (p *DefaultPath) Set(data common.ParserData, index int) error { + if data == nil { + p.Init() + return nil + } + switch newValue := data.(type) { + case *types.DefaultPath: + p.data = newValue + case types.DefaultPath: + p.data = &newValue + default: + return errors.ErrInvalidData + } + return nil +} + +func (p *DefaultPath) PreParse(line string, parts []string, preComments []string, comment string) (string, error) { + changeState, err := p.Parse(line, parts, comment) + if err == nil && preComments != nil { + p.preComments = append(p.preComments, preComments...) + } + return changeState, err +} + +func (p *DefaultPath) ResultAll() ([]common.ReturnResultLine, []string, error) { + res, err := p.Result() + return res, p.preComments, err +} diff --git a/config-parser/parsers/default-server.go b/config-parser/parsers/default-server.go new file mode 100644 index 00000000..06f9b847 --- /dev/null +++ b/config-parser/parsers/default-server.go @@ -0,0 +1,56 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package parsers + +import ( + "fmt" + + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/params" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +type DefaultServer struct { + data []types.DefaultServer + preComments []string // comments that appear before the actual line +} + +func (h *DefaultServer) parse(line string, parts []string, comment string) (*types.DefaultServer, error) { + if len(parts) >= 2 { + data := &types.DefaultServer{ + Params: params.ParseServerOptions(parts[1:]), + Comment: comment, + } + return data, nil + } + return nil, &errors.ParseError{Parser: "DefaultServer", Line: line} +} + +func (h *DefaultServer) Result() ([]common.ReturnResultLine, error) { + if len(h.data) == 0 { + return nil, errors.ErrFetch + } + result := make([]common.ReturnResultLine, len(h.data)) + for index, req := range h.data { + result[index] = common.ReturnResultLine{ + Data: fmt.Sprintf("default-server %s", params.ServerOptionsString(req.Params)), + Comment: req.Comment, + } + } + return result, nil +} diff --git a/config-parser/parsers/default-server_generated.go b/config-parser/parsers/default-server_generated.go new file mode 100644 index 00000000..84fb978e --- /dev/null +++ b/config-parser/parsers/default-server_generated.go @@ -0,0 +1,157 @@ +// Code generated by go generate; DO NOT EDIT. +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package parsers + +import ( + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +func (p *DefaultServer) Init() { + p.data = []types.DefaultServer{} + p.preComments = []string{} +} + +func (p *DefaultServer) GetParserName() string { + return "default-server" +} + +func (p *DefaultServer) Get(createIfNotExist bool) (common.ParserData, error) { + if len(p.data) == 0 && !createIfNotExist { + return nil, errors.ErrFetch + } + return p.data, nil +} + +func (p *DefaultServer) GetPreComments() ([]string, error) { + return p.preComments, nil +} + +func (p *DefaultServer) SetPreComments(preComments []string) { + p.preComments = preComments +} + +func (p *DefaultServer) GetOne(index int) (common.ParserData, error) { + if index < 0 || index >= len(p.data) { + return nil, errors.ErrFetch + } + return p.data[index], nil +} + +func (p *DefaultServer) Delete(index int) error { + if index < 0 || index >= len(p.data) { + return errors.ErrFetch + } + copy(p.data[index:], p.data[index+1:]) + p.data[len(p.data)-1] = types.DefaultServer{} + p.data = p.data[:len(p.data)-1] + return nil +} + +func (p *DefaultServer) Insert(data common.ParserData, index int) error { + if data == nil { + return errors.ErrInvalidData + } + switch newValue := data.(type) { + case []types.DefaultServer: + p.data = newValue + case *types.DefaultServer: + if index > -1 { + if index > len(p.data) { + return errors.ErrIndexOutOfRange + } + p.data = append(p.data, types.DefaultServer{}) + copy(p.data[index+1:], p.data[index:]) + p.data[index] = *newValue + } else { + p.data = append(p.data, *newValue) + } + case types.DefaultServer: + if index > -1 { + if index > len(p.data) { + return errors.ErrIndexOutOfRange + } + p.data = append(p.data, types.DefaultServer{}) + copy(p.data[index+1:], p.data[index:]) + p.data[index] = newValue + } else { + p.data = append(p.data, newValue) + } + default: + return errors.ErrInvalidData + } + return nil +} + +func (p *DefaultServer) Set(data common.ParserData, index int) error { + if data == nil { + p.Init() + return nil + } + switch newValue := data.(type) { + case []types.DefaultServer: + p.data = newValue + case *types.DefaultServer: + if index > -1 && index < len(p.data) { + p.data[index] = *newValue + } else if index == -1 { + p.data = append(p.data, *newValue) + } else { + return errors.ErrIndexOutOfRange + } + case types.DefaultServer: + if index > -1 && index < len(p.data) { + p.data[index] = newValue + } else if index == -1 { + p.data = append(p.data, newValue) + } else { + return errors.ErrIndexOutOfRange + } + default: + return errors.ErrInvalidData + } + return nil +} + +func (p *DefaultServer) PreParse(line string, parts []string, preComments []string, comment string) (string, error) { + changeState, err := p.Parse(line, parts, comment) + if err == nil && preComments != nil { + p.preComments = append(p.preComments, preComments...) + } + return changeState, err +} + +func (p *DefaultServer) Parse(line string, parts []string, comment string) (string, error) { + if parts[0] == "default-server" { + data, err := p.parse(line, parts, comment) + if err != nil { + if _, ok := err.(*errors.ParseError); ok { + return "", err + } + return "", &errors.ParseError{Parser: "DefaultServer", Line: line} + } + p.data = append(p.data, *data) + return "", nil + } + return "", &errors.ParseError{Parser: "DefaultServer", Line: line} +} + +func (p *DefaultServer) ResultAll() ([]common.ReturnResultLine, []string, error) { + res, err := p.Result() + return res, p.preComments, err +} diff --git a/config-parser/parsers/default_backend_generated.go b/config-parser/parsers/default_backend_generated.go new file mode 100644 index 00000000..04f469ec --- /dev/null +++ b/config-parser/parsers/default_backend_generated.go @@ -0,0 +1,99 @@ +// Code generated by go generate; DO NOT EDIT. +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package parsers + +import ( + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +func (p *DefaultBackend) Init() { + p.data = nil + p.preComments = []string{} +} + +func (p *DefaultBackend) GetParserName() string { + return "default_backend" +} + +func (p *DefaultBackend) Get(createIfNotExist bool) (common.ParserData, error) { + if p.data == nil { + if createIfNotExist { + p.data = &types.StringC{} + return p.data, nil + } + return nil, errors.ErrFetch + } + return p.data, nil +} + +func (p *DefaultBackend) GetPreComments() ([]string, error) { + return p.preComments, nil +} + +func (p *DefaultBackend) SetPreComments(preComments []string) { + p.preComments = preComments +} + +func (p *DefaultBackend) GetOne(index int) (common.ParserData, error) { + if index > 0 { + return nil, errors.ErrFetch + } + if p.data == nil { + return nil, errors.ErrFetch + } + return p.data, nil +} + +func (p *DefaultBackend) Delete(index int) error { + p.Init() + return nil +} + +func (p *DefaultBackend) Insert(data common.ParserData, index int) error { + return p.Set(data, index) +} + +func (p *DefaultBackend) Set(data common.ParserData, index int) error { + if data == nil { + p.Init() + return nil + } + switch newValue := data.(type) { + case *types.StringC: + p.data = newValue + case types.StringC: + p.data = &newValue + default: + return errors.ErrInvalidData + } + return nil +} + +func (p *DefaultBackend) PreParse(line string, parts []string, preComments []string, comment string) (string, error) { + changeState, err := p.Parse(line, parts, comment) + if err == nil && preComments != nil { + p.preComments = append(p.preComments, preComments...) + } + return changeState, err +} + +func (p *DefaultBackend) ResultAll() ([]common.ReturnResultLine, []string, error) { + res, err := p.Result() + return res, p.preComments, err +} diff --git a/config-parser/parsers/dgram-bind.go b/config-parser/parsers/dgram-bind.go new file mode 100644 index 00000000..6a0cbe93 --- /dev/null +++ b/config-parser/parsers/dgram-bind.go @@ -0,0 +1,67 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package parsers + +import ( + "strings" + + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/params" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +type DgramBind struct { + data []types.DgramBind + preComments []string // comments that appear before the actual line +} + +func (h *DgramBind) parse(line string, parts []string, comment string) (*types.DgramBind, error) { + if len(parts) >= 2 { + data := &types.DgramBind{ + Path: parts[1], + Comment: comment, + } + if len(parts) > 2 { + data.Params = params.ParseDgramBindOptions(parts[2:]) + } + return data, nil + } + return nil, &errors.ParseError{Parser: "DgramBindLines", Line: line} +} + +func (h *DgramBind) Result() ([]common.ReturnResultLine, error) { + if len(h.data) == 0 { + return nil, errors.ErrFetch + } + result := make([]common.ReturnResultLine, len(h.data)) + for index, req := range h.data { + var sb strings.Builder + sb.WriteString("dgram-bind ") + sb.WriteString(req.Path) + options := params.DgramBindOptionsString(req.Params) + if options != "" { + sb.WriteString(" ") + sb.WriteString(options) + } + result[index] = common.ReturnResultLine{ + Data: sb.String(), + Comment: req.Comment, + } + } + return result, nil +} diff --git a/config-parser/parsers/dgram-bind_generated.go b/config-parser/parsers/dgram-bind_generated.go new file mode 100644 index 00000000..2cd8b521 --- /dev/null +++ b/config-parser/parsers/dgram-bind_generated.go @@ -0,0 +1,157 @@ +// Code generated by go generate; DO NOT EDIT. +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package parsers + +import ( + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +func (p *DgramBind) Init() { + p.data = []types.DgramBind{} + p.preComments = []string{} +} + +func (p *DgramBind) GetParserName() string { + return "dgram-bind" +} + +func (p *DgramBind) Get(createIfNotExist bool) (common.ParserData, error) { + if len(p.data) == 0 && !createIfNotExist { + return nil, errors.ErrFetch + } + return p.data, nil +} + +func (p *DgramBind) GetPreComments() ([]string, error) { + return p.preComments, nil +} + +func (p *DgramBind) SetPreComments(preComments []string) { + p.preComments = preComments +} + +func (p *DgramBind) GetOne(index int) (common.ParserData, error) { + if index < 0 || index >= len(p.data) { + return nil, errors.ErrFetch + } + return p.data[index], nil +} + +func (p *DgramBind) Delete(index int) error { + if index < 0 || index >= len(p.data) { + return errors.ErrFetch + } + copy(p.data[index:], p.data[index+1:]) + p.data[len(p.data)-1] = types.DgramBind{} + p.data = p.data[:len(p.data)-1] + return nil +} + +func (p *DgramBind) Insert(data common.ParserData, index int) error { + if data == nil { + return errors.ErrInvalidData + } + switch newValue := data.(type) { + case []types.DgramBind: + p.data = newValue + case *types.DgramBind: + if index > -1 { + if index > len(p.data) { + return errors.ErrIndexOutOfRange + } + p.data = append(p.data, types.DgramBind{}) + copy(p.data[index+1:], p.data[index:]) + p.data[index] = *newValue + } else { + p.data = append(p.data, *newValue) + } + case types.DgramBind: + if index > -1 { + if index > len(p.data) { + return errors.ErrIndexOutOfRange + } + p.data = append(p.data, types.DgramBind{}) + copy(p.data[index+1:], p.data[index:]) + p.data[index] = newValue + } else { + p.data = append(p.data, newValue) + } + default: + return errors.ErrInvalidData + } + return nil +} + +func (p *DgramBind) Set(data common.ParserData, index int) error { + if data == nil { + p.Init() + return nil + } + switch newValue := data.(type) { + case []types.DgramBind: + p.data = newValue + case *types.DgramBind: + if index > -1 && index < len(p.data) { + p.data[index] = *newValue + } else if index == -1 { + p.data = append(p.data, *newValue) + } else { + return errors.ErrIndexOutOfRange + } + case types.DgramBind: + if index > -1 && index < len(p.data) { + p.data[index] = newValue + } else if index == -1 { + p.data = append(p.data, newValue) + } else { + return errors.ErrIndexOutOfRange + } + default: + return errors.ErrInvalidData + } + return nil +} + +func (p *DgramBind) PreParse(line string, parts []string, preComments []string, comment string) (string, error) { + changeState, err := p.Parse(line, parts, comment) + if err == nil && preComments != nil { + p.preComments = append(p.preComments, preComments...) + } + return changeState, err +} + +func (p *DgramBind) Parse(line string, parts []string, comment string) (string, error) { + if parts[0] == "dgram-bind" { + data, err := p.parse(line, parts, comment) + if err != nil { + if _, ok := err.(*errors.ParseError); ok { + return "", err + } + return "", &errors.ParseError{Parser: "DgramBind", Line: line} + } + p.data = append(p.data, *data) + return "", nil + } + return "", &errors.ParseError{Parser: "DgramBind", Line: line} +} + +func (p *DgramBind) ResultAll() ([]common.ReturnResultLine, []string, error) { + res, err := p.Result() + return res, p.preComments, err +} diff --git a/config-parser/parsers/email-alert.go b/config-parser/parsers/email-alert.go new file mode 100644 index 00000000..57aedcd4 --- /dev/null +++ b/config-parser/parsers/email-alert.go @@ -0,0 +1,75 @@ +/* +Copyright 2022 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package parsers + +import ( + "fmt" + "strings" + + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +type EmailAlert struct { + data []types.EmailAlert + preComments []string // comments that appear before the actual line +} + +func (e *EmailAlert) parse(line string, parts []string, comment string) (*types.EmailAlert, error) { + if len(parts) != 3 { + return nil, &errors.ParseError{Parser: "EmailAlert", Line: line} + } + + attr, value := parts[1], parts[2] + + switch attr { + case "from", "to": + if !strings.Contains(value, "@") { + return nil, &errors.ParseError{Parser: "EmailAlert", Line: line, Message: fmt.Sprintf("invalid email address: '%s'", value)} + } + case "level": + // Must be a valid syslog severity level. + if _, exists := logAllowedLevels[value]; !exists { + return nil, &errors.ParseError{Parser: "EmailAlert", Line: line, Message: fmt.Sprintf("invalid email-alert log level '%s'", value)} + } + case "mailers", "myhostname": + default: + return nil, &errors.ParseError{Parser: "EmailAlert", Line: line, Message: fmt.Sprintf("unknown email-alert attribute '%s'", attr)} + } + + data := &types.EmailAlert{ + Attribute: attr, + Value: value, + Comment: comment, + } + return data, nil +} + +func (e *EmailAlert) Result() ([]common.ReturnResultLine, error) { + if len(e.data) == 0 { + return nil, errors.ErrFetch + } + result := make([]common.ReturnResultLine, len(e.data)) + for index, ea := range e.data { + result[index] = common.ReturnResultLine{ + Data: fmt.Sprintf("email-alert %s %s", ea.Attribute, ea.Value), + Comment: ea.Comment, + } + } + return result, nil +} diff --git a/config-parser/parsers/email-alert_generated.go b/config-parser/parsers/email-alert_generated.go new file mode 100644 index 00000000..f754ab3b --- /dev/null +++ b/config-parser/parsers/email-alert_generated.go @@ -0,0 +1,157 @@ +// Code generated by go generate; DO NOT EDIT. +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package parsers + +import ( + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +func (p *EmailAlert) Init() { + p.data = []types.EmailAlert{} + p.preComments = []string{} +} + +func (p *EmailAlert) GetParserName() string { + return "email-alert" +} + +func (p *EmailAlert) Get(createIfNotExist bool) (common.ParserData, error) { + if len(p.data) == 0 && !createIfNotExist { + return nil, errors.ErrFetch + } + return p.data, nil +} + +func (p *EmailAlert) GetPreComments() ([]string, error) { + return p.preComments, nil +} + +func (p *EmailAlert) SetPreComments(preComments []string) { + p.preComments = preComments +} + +func (p *EmailAlert) GetOne(index int) (common.ParserData, error) { + if index < 0 || index >= len(p.data) { + return nil, errors.ErrFetch + } + return p.data[index], nil +} + +func (p *EmailAlert) Delete(index int) error { + if index < 0 || index >= len(p.data) { + return errors.ErrFetch + } + copy(p.data[index:], p.data[index+1:]) + p.data[len(p.data)-1] = types.EmailAlert{} + p.data = p.data[:len(p.data)-1] + return nil +} + +func (p *EmailAlert) Insert(data common.ParserData, index int) error { + if data == nil { + return errors.ErrInvalidData + } + switch newValue := data.(type) { + case []types.EmailAlert: + p.data = newValue + case *types.EmailAlert: + if index > -1 { + if index > len(p.data) { + return errors.ErrIndexOutOfRange + } + p.data = append(p.data, types.EmailAlert{}) + copy(p.data[index+1:], p.data[index:]) + p.data[index] = *newValue + } else { + p.data = append(p.data, *newValue) + } + case types.EmailAlert: + if index > -1 { + if index > len(p.data) { + return errors.ErrIndexOutOfRange + } + p.data = append(p.data, types.EmailAlert{}) + copy(p.data[index+1:], p.data[index:]) + p.data[index] = newValue + } else { + p.data = append(p.data, newValue) + } + default: + return errors.ErrInvalidData + } + return nil +} + +func (p *EmailAlert) Set(data common.ParserData, index int) error { + if data == nil { + p.Init() + return nil + } + switch newValue := data.(type) { + case []types.EmailAlert: + p.data = newValue + case *types.EmailAlert: + if index > -1 && index < len(p.data) { + p.data[index] = *newValue + } else if index == -1 { + p.data = append(p.data, *newValue) + } else { + return errors.ErrIndexOutOfRange + } + case types.EmailAlert: + if index > -1 && index < len(p.data) { + p.data[index] = newValue + } else if index == -1 { + p.data = append(p.data, newValue) + } else { + return errors.ErrIndexOutOfRange + } + default: + return errors.ErrInvalidData + } + return nil +} + +func (p *EmailAlert) PreParse(line string, parts []string, preComments []string, comment string) (string, error) { + changeState, err := p.Parse(line, parts, comment) + if err == nil && preComments != nil { + p.preComments = append(p.preComments, preComments...) + } + return changeState, err +} + +func (p *EmailAlert) Parse(line string, parts []string, comment string) (string, error) { + if parts[0] == "email-alert" { + data, err := p.parse(line, parts, comment) + if err != nil { + if _, ok := err.(*errors.ParseError); ok { + return "", err + } + return "", &errors.ParseError{Parser: "EmailAlert", Line: line} + } + p.data = append(p.data, *data) + return "", nil + } + return "", &errors.ParseError{Parser: "EmailAlert", Line: line} +} + +func (p *EmailAlert) ResultAll() ([]common.ReturnResultLine, []string, error) { + res, err := p.Result() + return res, p.preComments, err +} diff --git a/config-parser/parsers/errorfile.go b/config-parser/parsers/errorfile.go new file mode 100644 index 00000000..6f4f9e19 --- /dev/null +++ b/config-parser/parsers/errorfile.go @@ -0,0 +1,87 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package parsers + +import ( + "fmt" + + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +// 200, 400, 401, 403, 404, 405, 407, 408, 410, +// 413, 425, 429, 500, 501, 502, 503, and 504 +var errorFileAllowedCode = map[string]struct{}{ //nolint:gochecknoglobals + "200": {}, + "400": {}, + "401": {}, + "403": {}, + "404": {}, + "405": {}, + "407": {}, + "408": {}, + "410": {}, + "413": {}, + "425": {}, + "429": {}, + "500": {}, + "501": {}, + "502": {}, + "503": {}, + "504": {}, +} + +type ErrorFile struct { + data []types.ErrorFile + preComments []string // comments that appear before the actual line +} + +func (l *ErrorFile) Init() { + l.data = []types.ErrorFile{} + l.preComments = []string{} +} + +func (l *ErrorFile) parse(line string, parts []string, comment string) (*types.ErrorFile, error) { + if len(parts) < 3 { + return nil, &errors.ParseError{Parser: "ErrorFile", Line: line} + } + errorfile := &types.ErrorFile{ + File: parts[2], + Comment: comment, + } + code := parts[1] + if _, ok := errorFileAllowedCode[code]; !ok { + return nil, &errors.ParseError{Parser: "ErrorFile", Line: line} + } + errorfile.Code = code + return errorfile, nil +} + +func (l *ErrorFile) Result() ([]common.ReturnResultLine, error) { + if len(l.data) == 0 { + return nil, errors.ErrFetch + } + result := make([]common.ReturnResultLine, len(l.data)) + for index, data := range l.data { + result[index] = common.ReturnResultLine{ + Data: fmt.Sprintf("errorfile %s %s", data.Code, data.File), + Comment: data.Comment, + } + } + return result, nil +} diff --git a/config-parser/parsers/errorfile_generated.go b/config-parser/parsers/errorfile_generated.go new file mode 100644 index 00000000..24f0eb8a --- /dev/null +++ b/config-parser/parsers/errorfile_generated.go @@ -0,0 +1,152 @@ +// Code generated by go generate; DO NOT EDIT. +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package parsers + +import ( + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +func (p *ErrorFile) GetParserName() string { + return "errorfile" +} + +func (p *ErrorFile) Get(createIfNotExist bool) (common.ParserData, error) { + if len(p.data) == 0 && !createIfNotExist { + return nil, errors.ErrFetch + } + return p.data, nil +} + +func (p *ErrorFile) GetPreComments() ([]string, error) { + return p.preComments, nil +} + +func (p *ErrorFile) SetPreComments(preComments []string) { + p.preComments = preComments +} + +func (p *ErrorFile) GetOne(index int) (common.ParserData, error) { + if index < 0 || index >= len(p.data) { + return nil, errors.ErrFetch + } + return p.data[index], nil +} + +func (p *ErrorFile) Delete(index int) error { + if index < 0 || index >= len(p.data) { + return errors.ErrFetch + } + copy(p.data[index:], p.data[index+1:]) + p.data[len(p.data)-1] = types.ErrorFile{} + p.data = p.data[:len(p.data)-1] + return nil +} + +func (p *ErrorFile) Insert(data common.ParserData, index int) error { + if data == nil { + return errors.ErrInvalidData + } + switch newValue := data.(type) { + case []types.ErrorFile: + p.data = newValue + case *types.ErrorFile: + if index > -1 { + if index > len(p.data) { + return errors.ErrIndexOutOfRange + } + p.data = append(p.data, types.ErrorFile{}) + copy(p.data[index+1:], p.data[index:]) + p.data[index] = *newValue + } else { + p.data = append(p.data, *newValue) + } + case types.ErrorFile: + if index > -1 { + if index > len(p.data) { + return errors.ErrIndexOutOfRange + } + p.data = append(p.data, types.ErrorFile{}) + copy(p.data[index+1:], p.data[index:]) + p.data[index] = newValue + } else { + p.data = append(p.data, newValue) + } + default: + return errors.ErrInvalidData + } + return nil +} + +func (p *ErrorFile) Set(data common.ParserData, index int) error { + if data == nil { + p.Init() + return nil + } + switch newValue := data.(type) { + case []types.ErrorFile: + p.data = newValue + case *types.ErrorFile: + if index > -1 && index < len(p.data) { + p.data[index] = *newValue + } else if index == -1 { + p.data = append(p.data, *newValue) + } else { + return errors.ErrIndexOutOfRange + } + case types.ErrorFile: + if index > -1 && index < len(p.data) { + p.data[index] = newValue + } else if index == -1 { + p.data = append(p.data, newValue) + } else { + return errors.ErrIndexOutOfRange + } + default: + return errors.ErrInvalidData + } + return nil +} + +func (p *ErrorFile) PreParse(line string, parts []string, preComments []string, comment string) (string, error) { + changeState, err := p.Parse(line, parts, comment) + if err == nil && preComments != nil { + p.preComments = append(p.preComments, preComments...) + } + return changeState, err +} + +func (p *ErrorFile) Parse(line string, parts []string, comment string) (string, error) { + if parts[0] == "errorfile" { + data, err := p.parse(line, parts, comment) + if err != nil { + if _, ok := err.(*errors.ParseError); ok { + return "", err + } + return "", &errors.ParseError{Parser: "ErrorFile", Line: line} + } + p.data = append(p.data, *data) + return "", nil + } + return "", &errors.ParseError{Parser: "ErrorFile", Line: line} +} + +func (p *ErrorFile) ResultAll() ([]common.ReturnResultLine, []string, error) { + res, err := p.Result() + return res, p.preComments, err +} diff --git a/config-parser/parsers/errorfiles.go b/config-parser/parsers/errorfiles.go new file mode 100644 index 00000000..c286bba9 --- /dev/null +++ b/config-parser/parsers/errorfiles.go @@ -0,0 +1,81 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package parsers + +import ( + "fmt" + "strconv" + + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +type ErrorFiles struct { + data []types.ErrorFiles + preComments []string // comments that appear before the actual line +} + +func (e *ErrorFiles) Init() { + e.data = []types.ErrorFiles{} + e.preComments = []string{} +} + +func (e *ErrorFiles) parse(line string, parts []string, comment string) (*types.ErrorFiles, error) { + if len(parts) < 2 { + return nil, &errors.ParseError{Parser: "ErrorFiles", Line: line} + } + errorfiles := &types.ErrorFiles{ + Name: parts[1], + Comment: comment, + } + if len(parts) > 2 { + codes := make([]int64, len(parts)-2) + for i, code := range parts[2:] { + if _, ok := errorFileAllowedCode[code]; !ok { + return nil, &errors.ParseError{Parser: "ErrorFiles", Line: line} + } + intCode, err := strconv.ParseInt(code, 10, 0) + if err != nil { + return nil, &errors.ParseError{Parser: "ErrorFiles", Line: line} + } + codes[i] = intCode + } + errorfiles.Codes = codes + } + return errorfiles, nil +} + +func (e *ErrorFiles) Result() ([]common.ReturnResultLine, error) { + if len(e.data) == 0 { + return nil, errors.ErrFetch + } + result := make([]common.ReturnResultLine, len(e.data)) + for index, data := range e.data { + + result[index] = common.ReturnResultLine{ + Data: fmt.Sprintf("errorfiles %s", data.Name), + Comment: data.Comment, + } + if len(data.Codes) > 0 { + for _, code := range data.Codes { + result[index].Data = fmt.Sprintf("%s %s", result[index].Data, strconv.FormatInt(code, 10)) + } + } + } + return result, nil +} diff --git a/config-parser/parsers/errorfiles_generated.go b/config-parser/parsers/errorfiles_generated.go new file mode 100644 index 00000000..e656d0dd --- /dev/null +++ b/config-parser/parsers/errorfiles_generated.go @@ -0,0 +1,152 @@ +// Code generated by go generate; DO NOT EDIT. +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package parsers + +import ( + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +func (p *ErrorFiles) GetParserName() string { + return "errorfiles" +} + +func (p *ErrorFiles) Get(createIfNotExist bool) (common.ParserData, error) { + if len(p.data) == 0 && !createIfNotExist { + return nil, errors.ErrFetch + } + return p.data, nil +} + +func (p *ErrorFiles) GetPreComments() ([]string, error) { + return p.preComments, nil +} + +func (p *ErrorFiles) SetPreComments(preComments []string) { + p.preComments = preComments +} + +func (p *ErrorFiles) GetOne(index int) (common.ParserData, error) { + if index < 0 || index >= len(p.data) { + return nil, errors.ErrFetch + } + return p.data[index], nil +} + +func (p *ErrorFiles) Delete(index int) error { + if index < 0 || index >= len(p.data) { + return errors.ErrFetch + } + copy(p.data[index:], p.data[index+1:]) + p.data[len(p.data)-1] = types.ErrorFiles{} + p.data = p.data[:len(p.data)-1] + return nil +} + +func (p *ErrorFiles) Insert(data common.ParserData, index int) error { + if data == nil { + return errors.ErrInvalidData + } + switch newValue := data.(type) { + case []types.ErrorFiles: + p.data = newValue + case *types.ErrorFiles: + if index > -1 { + if index > len(p.data) { + return errors.ErrIndexOutOfRange + } + p.data = append(p.data, types.ErrorFiles{}) + copy(p.data[index+1:], p.data[index:]) + p.data[index] = *newValue + } else { + p.data = append(p.data, *newValue) + } + case types.ErrorFiles: + if index > -1 { + if index > len(p.data) { + return errors.ErrIndexOutOfRange + } + p.data = append(p.data, types.ErrorFiles{}) + copy(p.data[index+1:], p.data[index:]) + p.data[index] = newValue + } else { + p.data = append(p.data, newValue) + } + default: + return errors.ErrInvalidData + } + return nil +} + +func (p *ErrorFiles) Set(data common.ParserData, index int) error { + if data == nil { + p.Init() + return nil + } + switch newValue := data.(type) { + case []types.ErrorFiles: + p.data = newValue + case *types.ErrorFiles: + if index > -1 && index < len(p.data) { + p.data[index] = *newValue + } else if index == -1 { + p.data = append(p.data, *newValue) + } else { + return errors.ErrIndexOutOfRange + } + case types.ErrorFiles: + if index > -1 && index < len(p.data) { + p.data[index] = newValue + } else if index == -1 { + p.data = append(p.data, newValue) + } else { + return errors.ErrIndexOutOfRange + } + default: + return errors.ErrInvalidData + } + return nil +} + +func (p *ErrorFiles) PreParse(line string, parts []string, preComments []string, comment string) (string, error) { + changeState, err := p.Parse(line, parts, comment) + if err == nil && preComments != nil { + p.preComments = append(p.preComments, preComments...) + } + return changeState, err +} + +func (p *ErrorFiles) Parse(line string, parts []string, comment string) (string, error) { + if parts[0] == "errorfiles" { + data, err := p.parse(line, parts, comment) + if err != nil { + if _, ok := err.(*errors.ParseError); ok { + return "", err + } + return "", &errors.ParseError{Parser: "ErrorFiles", Line: line} + } + p.data = append(p.data, *data) + return "", nil + } + return "", &errors.ParseError{Parser: "ErrorFiles", Line: line} +} + +func (p *ErrorFiles) ResultAll() ([]common.ReturnResultLine, []string, error) { + res, err := p.Result() + return res, p.preComments, err +} diff --git a/config-parser/parsers/errorloc302.go b/config-parser/parsers/errorloc302.go new file mode 100644 index 00000000..01cc7705 --- /dev/null +++ b/config-parser/parsers/errorloc302.go @@ -0,0 +1,59 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package parsers + +import ( + "fmt" + + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +type ErrorLoc302 struct { + data *types.ErrorLoc302 + preComments []string // comments that appear before the actual line +} + +func (l *ErrorLoc302) Parse(line string, parts []string, comment string) (string, error) { + if len(parts) < 3 { + return "", &errors.ParseError{Parser: "ErrorLoc302", Line: line} + } + errorLoc := &types.ErrorLoc302{ + URL: parts[2], + Comment: comment, + } + code := parts[1] + if _, ok := errorFileAllowedCode[code]; !ok { + return "", &errors.ParseError{Parser: "ErrorLoc302", Line: line} + } + errorLoc.Code = code + l.data = errorLoc + return "", nil +} + +func (l *ErrorLoc302) Result() ([]common.ReturnResultLine, error) { + if l.data == nil { + return nil, errors.ErrFetch + } + return []common.ReturnResultLine{ + { + Data: fmt.Sprintf("errorloc302 %s %s", l.data.Code, l.data.URL), + Comment: l.data.Comment, + }, + }, nil +} diff --git a/config-parser/parsers/errorloc302_generated.go b/config-parser/parsers/errorloc302_generated.go new file mode 100644 index 00000000..dcfd40cb --- /dev/null +++ b/config-parser/parsers/errorloc302_generated.go @@ -0,0 +1,99 @@ +// Code generated by go generate; DO NOT EDIT. +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package parsers + +import ( + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +func (p *ErrorLoc302) Init() { + p.data = nil + p.preComments = []string{} +} + +func (p *ErrorLoc302) GetParserName() string { + return "errorloc302" +} + +func (p *ErrorLoc302) Get(createIfNotExist bool) (common.ParserData, error) { + if p.data == nil { + if createIfNotExist { + p.data = &types.ErrorLoc302{} + return p.data, nil + } + return nil, errors.ErrFetch + } + return p.data, nil +} + +func (p *ErrorLoc302) GetPreComments() ([]string, error) { + return p.preComments, nil +} + +func (p *ErrorLoc302) SetPreComments(preComments []string) { + p.preComments = preComments +} + +func (p *ErrorLoc302) GetOne(index int) (common.ParserData, error) { + if index > 0 { + return nil, errors.ErrFetch + } + if p.data == nil { + return nil, errors.ErrFetch + } + return p.data, nil +} + +func (p *ErrorLoc302) Delete(index int) error { + p.Init() + return nil +} + +func (p *ErrorLoc302) Insert(data common.ParserData, index int) error { + return p.Set(data, index) +} + +func (p *ErrorLoc302) Set(data common.ParserData, index int) error { + if data == nil { + p.Init() + return nil + } + switch newValue := data.(type) { + case *types.ErrorLoc302: + p.data = newValue + case types.ErrorLoc302: + p.data = &newValue + default: + return errors.ErrInvalidData + } + return nil +} + +func (p *ErrorLoc302) PreParse(line string, parts []string, preComments []string, comment string) (string, error) { + changeState, err := p.Parse(line, parts, comment) + if err == nil && preComments != nil { + p.preComments = append(p.preComments, preComments...) + } + return changeState, err +} + +func (p *ErrorLoc302) ResultAll() ([]common.ReturnResultLine, []string, error) { + res, err := p.Result() + return res, p.preComments, err +} diff --git a/config-parser/parsers/errorloc303.go b/config-parser/parsers/errorloc303.go new file mode 100644 index 00000000..21fbc55e --- /dev/null +++ b/config-parser/parsers/errorloc303.go @@ -0,0 +1,54 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package parsers + +import ( + "fmt" + + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +type ErrorLoc303 struct { + data *types.ErrorLoc303 + preComments []string // comments that appear before the actual line +} + +func (l *ErrorLoc303) Parse(line string, parts []string, comment string) (string, error) { + if len(parts) < 3 { + return "", &errors.ParseError{Parser: "ErrorLoc303", Line: line} + } + errorLoc := &types.ErrorLoc303{ + URL: parts[2], + Comment: comment, + } + code := parts[1] + if _, ok := errorFileAllowedCode[code]; !ok { + return "", &errors.ParseError{Parser: "ErrorLoc303", Line: line} + } + errorLoc.Code = code + l.data = errorLoc + return "", nil +} + +func (l *ErrorLoc303) Result() ([]common.ReturnResultLine, error) { + if l.data == nil { + return nil, errors.ErrFetch + } + return []common.ReturnResultLine{{Data: fmt.Sprintf("errorloc303 %s %s", l.data.Code, l.data.URL), Comment: l.data.Comment}}, nil +} diff --git a/config-parser/parsers/errorloc303_generated.go b/config-parser/parsers/errorloc303_generated.go new file mode 100644 index 00000000..b6540ebd --- /dev/null +++ b/config-parser/parsers/errorloc303_generated.go @@ -0,0 +1,99 @@ +// Code generated by go generate; DO NOT EDIT. +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package parsers + +import ( + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +func (p *ErrorLoc303) Init() { + p.data = nil + p.preComments = []string{} +} + +func (p *ErrorLoc303) GetParserName() string { + return "errorloc303" +} + +func (p *ErrorLoc303) Get(createIfNotExist bool) (common.ParserData, error) { + if p.data == nil { + if createIfNotExist { + p.data = &types.ErrorLoc303{} + return p.data, nil + } + return nil, errors.ErrFetch + } + return p.data, nil +} + +func (p *ErrorLoc303) GetPreComments() ([]string, error) { + return p.preComments, nil +} + +func (p *ErrorLoc303) SetPreComments(preComments []string) { + p.preComments = preComments +} + +func (p *ErrorLoc303) GetOne(index int) (common.ParserData, error) { + if index > 0 { + return nil, errors.ErrFetch + } + if p.data == nil { + return nil, errors.ErrFetch + } + return p.data, nil +} + +func (p *ErrorLoc303) Delete(index int) error { + p.Init() + return nil +} + +func (p *ErrorLoc303) Insert(data common.ParserData, index int) error { + return p.Set(data, index) +} + +func (p *ErrorLoc303) Set(data common.ParserData, index int) error { + if data == nil { + p.Init() + return nil + } + switch newValue := data.(type) { + case *types.ErrorLoc303: + p.data = newValue + case types.ErrorLoc303: + p.data = &newValue + default: + return errors.ErrInvalidData + } + return nil +} + +func (p *ErrorLoc303) PreParse(line string, parts []string, preComments []string, comment string) (string, error) { + changeState, err := p.Parse(line, parts, comment) + if err == nil && preComments != nil { + p.preComments = append(p.preComments, preComments...) + } + return changeState, err +} + +func (p *ErrorLoc303) ResultAll() ([]common.ReturnResultLine, []string, error) { + res, err := p.Result() + return res, p.preComments, err +} diff --git a/config-parser/parsers/external-check-command.go b/config-parser/parsers/external-check-command.go new file mode 100644 index 00000000..13827d63 --- /dev/null +++ b/config-parser/parsers/external-check-command.go @@ -0,0 +1,60 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package parsers + +import ( + "fmt" + + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +const ExternalCheckKeyword = "external-check" + +type ExternalCheckCommand struct { + data *types.ExternalCheckCommand + preComments []string // comments that appear before the actual line +} + +// external-check command +func (s *ExternalCheckCommand) Parse(line string, parts []string, comment string) (string, error) { + if len(parts) == 3 && parts[0] == "external-check" && parts[1] == "command" { + s.data = &types.ExternalCheckCommand{ + Command: parts[2], + Comment: comment, + } + return "", nil + } + return "", &errors.ParseError{Parser: "external-check command", Line: line} +} + +func (s *ExternalCheckCommand) Result() ([]common.ReturnResultLine, error) { + if s.data == nil { + return nil, errors.ErrFetch + } + var data string + if s.data.Command != "" { + data = fmt.Sprintf("external-check command %s", s.data.Command) + } + return []common.ReturnResultLine{ + { + Data: data, + Comment: s.data.Comment, + }, + }, nil +} diff --git a/config-parser/parsers/external-check-command_generated.go b/config-parser/parsers/external-check-command_generated.go new file mode 100644 index 00000000..f36e358a --- /dev/null +++ b/config-parser/parsers/external-check-command_generated.go @@ -0,0 +1,99 @@ +// Code generated by go generate; DO NOT EDIT. +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package parsers + +import ( + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +func (p *ExternalCheckCommand) Init() { + p.data = nil + p.preComments = []string{} +} + +func (p *ExternalCheckCommand) GetParserName() string { + return "external-check command" +} + +func (p *ExternalCheckCommand) Get(createIfNotExist bool) (common.ParserData, error) { + if p.data == nil { + if createIfNotExist { + p.data = &types.ExternalCheckCommand{} + return p.data, nil + } + return nil, errors.ErrFetch + } + return p.data, nil +} + +func (p *ExternalCheckCommand) GetPreComments() ([]string, error) { + return p.preComments, nil +} + +func (p *ExternalCheckCommand) SetPreComments(preComments []string) { + p.preComments = preComments +} + +func (p *ExternalCheckCommand) GetOne(index int) (common.ParserData, error) { + if index > 0 { + return nil, errors.ErrFetch + } + if p.data == nil { + return nil, errors.ErrFetch + } + return p.data, nil +} + +func (p *ExternalCheckCommand) Delete(index int) error { + p.Init() + return nil +} + +func (p *ExternalCheckCommand) Insert(data common.ParserData, index int) error { + return p.Set(data, index) +} + +func (p *ExternalCheckCommand) Set(data common.ParserData, index int) error { + if data == nil { + p.Init() + return nil + } + switch newValue := data.(type) { + case *types.ExternalCheckCommand: + p.data = newValue + case types.ExternalCheckCommand: + p.data = &newValue + default: + return errors.ErrInvalidData + } + return nil +} + +func (p *ExternalCheckCommand) PreParse(line string, parts []string, preComments []string, comment string) (string, error) { + changeState, err := p.Parse(line, parts, comment) + if err == nil && preComments != nil { + p.preComments = append(p.preComments, preComments...) + } + return changeState, err +} + +func (p *ExternalCheckCommand) ResultAll() ([]common.ReturnResultLine, []string, error) { + res, err := p.Result() + return res, p.preComments, err +} diff --git a/config-parser/parsers/external-check-path.go b/config-parser/parsers/external-check-path.go new file mode 100644 index 00000000..e035b2d3 --- /dev/null +++ b/config-parser/parsers/external-check-path.go @@ -0,0 +1,60 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package parsers + +import ( + "fmt" + + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +type ExternalCheckPath struct { + data *types.ExternalCheckPath + preComments []string // comments that appear before the actual line +} + +/* +external-check path +*/ +func (s *ExternalCheckPath) Parse(line string, parts []string, comment string) (string, error) { + if len(parts) == 3 && parts[0] == "external-check" && parts[1] == "path" { + s.data = &types.ExternalCheckPath{ + Path: parts[2], + Comment: comment, + } + return "", nil + } + return "", &errors.ParseError{Parser: "external-check path", Line: line} +} + +func (s *ExternalCheckPath) Result() ([]common.ReturnResultLine, error) { + if s.data == nil { + return nil, errors.ErrFetch + } + var data string + if s.data.Path != "" { + data = fmt.Sprintf("external-check path %s", s.data.Path) + } + return []common.ReturnResultLine{ + { + Data: data, + Comment: s.data.Comment, + }, + }, nil +} diff --git a/config-parser/parsers/external-check-path_generated.go b/config-parser/parsers/external-check-path_generated.go new file mode 100644 index 00000000..2fa91002 --- /dev/null +++ b/config-parser/parsers/external-check-path_generated.go @@ -0,0 +1,99 @@ +// Code generated by go generate; DO NOT EDIT. +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package parsers + +import ( + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +func (p *ExternalCheckPath) Init() { + p.data = nil + p.preComments = []string{} +} + +func (p *ExternalCheckPath) GetParserName() string { + return "external-check path" +} + +func (p *ExternalCheckPath) Get(createIfNotExist bool) (common.ParserData, error) { + if p.data == nil { + if createIfNotExist { + p.data = &types.ExternalCheckPath{} + return p.data, nil + } + return nil, errors.ErrFetch + } + return p.data, nil +} + +func (p *ExternalCheckPath) GetPreComments() ([]string, error) { + return p.preComments, nil +} + +func (p *ExternalCheckPath) SetPreComments(preComments []string) { + p.preComments = preComments +} + +func (p *ExternalCheckPath) GetOne(index int) (common.ParserData, error) { + if index > 0 { + return nil, errors.ErrFetch + } + if p.data == nil { + return nil, errors.ErrFetch + } + return p.data, nil +} + +func (p *ExternalCheckPath) Delete(index int) error { + p.Init() + return nil +} + +func (p *ExternalCheckPath) Insert(data common.ParserData, index int) error { + return p.Set(data, index) +} + +func (p *ExternalCheckPath) Set(data common.ParserData, index int) error { + if data == nil { + p.Init() + return nil + } + switch newValue := data.(type) { + case *types.ExternalCheckPath: + p.data = newValue + case types.ExternalCheckPath: + p.data = &newValue + default: + return errors.ErrInvalidData + } + return nil +} + +func (p *ExternalCheckPath) PreParse(line string, parts []string, preComments []string, comment string) (string, error) { + changeState, err := p.Parse(line, parts, comment) + if err == nil && preComments != nil { + p.preComments = append(p.preComments, preComments...) + } + return changeState, err +} + +func (p *ExternalCheckPath) ResultAll() ([]common.ReturnResultLine, []string, error) { + res, err := p.Result() + return res, p.preComments, err +} diff --git a/config-parser/parsers/external-check.go b/config-parser/parsers/external-check.go new file mode 100644 index 00000000..9f56cfb9 --- /dev/null +++ b/config-parser/parsers/external-check.go @@ -0,0 +1,50 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package parsers + +import ( + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +type ExternalCheck struct { + data *types.Enabled + preComments []string // comments that appear before the actual line +} + +func (m *ExternalCheck) Parse(line string, parts []string, comment string) (string, error) { + if parts[0] == "external-check" { + m.data = &types.Enabled{ + Comment: comment, + } + return "", nil + } + return "", &errors.ParseError{Parser: "ExternalCheck", Line: line} +} + +func (m *ExternalCheck) Result() ([]common.ReturnResultLine, error) { + if m.data == nil { + return nil, errors.ErrFetch + } + return []common.ReturnResultLine{ + { + Data: "external-check", + Comment: m.data.Comment, + }, + }, nil +} diff --git a/config-parser/parsers/external-check_generated.go b/config-parser/parsers/external-check_generated.go new file mode 100644 index 00000000..f6123861 --- /dev/null +++ b/config-parser/parsers/external-check_generated.go @@ -0,0 +1,99 @@ +// Code generated by go generate; DO NOT EDIT. +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package parsers + +import ( + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +func (p *ExternalCheck) Init() { + p.data = nil + p.preComments = []string{} +} + +func (p *ExternalCheck) GetParserName() string { + return "external-check" +} + +func (p *ExternalCheck) Get(createIfNotExist bool) (common.ParserData, error) { + if p.data == nil { + if createIfNotExist { + p.data = &types.Enabled{} + return p.data, nil + } + return nil, errors.ErrFetch + } + return p.data, nil +} + +func (p *ExternalCheck) GetPreComments() ([]string, error) { + return p.preComments, nil +} + +func (p *ExternalCheck) SetPreComments(preComments []string) { + p.preComments = preComments +} + +func (p *ExternalCheck) GetOne(index int) (common.ParserData, error) { + if index > 0 { + return nil, errors.ErrFetch + } + if p.data == nil { + return nil, errors.ErrFetch + } + return p.data, nil +} + +func (p *ExternalCheck) Delete(index int) error { + p.Init() + return nil +} + +func (p *ExternalCheck) Insert(data common.ParserData, index int) error { + return p.Set(data, index) +} + +func (p *ExternalCheck) Set(data common.ParserData, index int) error { + if data == nil { + p.Init() + return nil + } + switch newValue := data.(type) { + case *types.Enabled: + p.data = newValue + case types.Enabled: + p.data = &newValue + default: + return errors.ErrInvalidData + } + return nil +} + +func (p *ExternalCheck) PreParse(line string, parts []string, preComments []string, comment string) (string, error) { + changeState, err := p.Parse(line, parts, comment) + if err == nil && preComments != nil { + p.preComments = append(p.preComments, preComments...) + } + return changeState, err +} + +func (p *ExternalCheck) ResultAll() ([]common.ReturnResultLine, []string, error) { + res, err := p.Result() + return res, p.preComments, err +} diff --git a/config-parser/parsers/extra/comments.go b/config-parser/parsers/extra/comments.go new file mode 100644 index 00000000..bee4bc86 --- /dev/null +++ b/config-parser/parsers/extra/comments.go @@ -0,0 +1,58 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package extra + +import ( + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +type Comments struct { + Name string + data []types.Comments + preComments []string +} + +func (p *Comments) Init() { + p.Name = "#" + p.data = []types.Comments{} +} + +func (p *Comments) Parse(line string, parts []string, comment string) (string, error) { + if line[0] == '#' { + p.data = append(p.data, types.Comments{ + Value: comment, + }) + return "", nil + } + return "", &errors.ParseError{Parser: "Comments", Line: line} +} + +func (p *Comments) Result() ([]common.ReturnResultLine, error) { + if len(p.data) == 0 { + return nil, errors.ErrFetch + } + result := make([]common.ReturnResultLine, len(p.data)) + for index, comment := range p.data { + result[index] = common.ReturnResultLine{ + Data: "# " + comment.Value, + Comment: "", + } + } + return result, nil +} diff --git a/config-parser/parsers/extra/comments_generated.go b/config-parser/parsers/extra/comments_generated.go new file mode 100644 index 00000000..7b7facb0 --- /dev/null +++ b/config-parser/parsers/extra/comments_generated.go @@ -0,0 +1,137 @@ +// Code generated by go generate; DO NOT EDIT. +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package extra + +import ( + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +func (p *Comments) GetParserName() string { + return p.Name +} + +func (p *Comments) Get(createIfNotExist bool) (common.ParserData, error) { + if len(p.data) == 0 && !createIfNotExist { + return nil, errors.ErrFetch + } + return p.data, nil +} + +func (p *Comments) GetPreComments() ([]string, error) { + return p.preComments, nil +} + +func (p *Comments) SetPreComments(preComments []string) { + p.preComments = preComments +} + +func (p *Comments) GetOne(index int) (common.ParserData, error) { + if index < 0 || index >= len(p.data) { + return nil, errors.ErrFetch + } + return p.data[index], nil +} + +func (p *Comments) Delete(index int) error { + if index < 0 || index >= len(p.data) { + return errors.ErrFetch + } + copy(p.data[index:], p.data[index+1:]) + p.data[len(p.data)-1] = types.Comments{} + p.data = p.data[:len(p.data)-1] + return nil +} + +func (p *Comments) Insert(data common.ParserData, index int) error { + if data == nil { + return errors.ErrInvalidData + } + switch newValue := data.(type) { + case []types.Comments: + p.data = newValue + case *types.Comments: + if index > -1 { + if index > len(p.data) { + return errors.ErrIndexOutOfRange + } + p.data = append(p.data, types.Comments{}) + copy(p.data[index+1:], p.data[index:]) + p.data[index] = *newValue + } else { + p.data = append(p.data, *newValue) + } + case types.Comments: + if index > -1 { + if index > len(p.data) { + return errors.ErrIndexOutOfRange + } + p.data = append(p.data, types.Comments{}) + copy(p.data[index+1:], p.data[index:]) + p.data[index] = newValue + } else { + p.data = append(p.data, newValue) + } + default: + return errors.ErrInvalidData + } + return nil +} + +func (p *Comments) Set(data common.ParserData, index int) error { + if data == nil { + p.Init() + return nil + } + switch newValue := data.(type) { + case []types.Comments: + p.data = newValue + case *types.Comments: + if index > -1 && index < len(p.data) { + p.data[index] = *newValue + } else if index == -1 { + p.data = append(p.data, *newValue) + } else { + return errors.ErrIndexOutOfRange + } + case types.Comments: + if index > -1 && index < len(p.data) { + p.data[index] = newValue + } else if index == -1 { + p.data = append(p.data, newValue) + } else { + return errors.ErrIndexOutOfRange + } + default: + return errors.ErrInvalidData + } + return nil +} + +func (p *Comments) PreParse(line string, parts []string, preComments []string, comment string) (string, error) { + changeState, err := p.Parse(line, parts, comment) + if err == nil && preComments != nil { + p.preComments = append(p.preComments, preComments...) + } + return changeState, err +} + +func (p *Comments) ResultAll() ([]common.ReturnResultLine, []string, error) { + res, err := p.Result() + return res, p.preComments, err +} diff --git a/config-parser/parsers/extra/config-hash.go b/config-parser/parsers/extra/config-hash.go new file mode 100644 index 00000000..25da71cd --- /dev/null +++ b/config-parser/parsers/extra/config-hash.go @@ -0,0 +1,69 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package extra + +import ( + "fmt" + "strings" + + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +type ConfigHash struct { + Name string + // Mode string + data *types.ConfigHash + preComments []string // comments that appear before the actual line +} + +func (h *ConfigHash) Init() { + h.Name = "# _md5hash" + h.data = nil +} + +func (h *ConfigHash) Get(createIfNotExist bool) (common.ParserData, error) { + if h.data != nil { + return h.data, nil + } else if createIfNotExist { + h.data = &types.ConfigHash{ + Value: "", + } + return h.data, nil + } + return nil, fmt.Errorf("no data") +} + +// Parse see if we have version, since it is not haproxy keyword, it's in comments +func (h *ConfigHash) Parse(line string, parts []string, comment string) (string, error) { + if strings.HasPrefix(comment, "_md5hash") { + data := common.StringSplitIgnoreEmpty(comment, '=') + if len(data) < 2 { + return "", &errors.ParseError{Parser: "ConfigHash", Line: line} + } + h.data = &types.ConfigHash{ + Value: data[1], + } + + return "", nil + } + return "", &errors.ParseError{Parser: "ConfigHash", Line: line} +} + +func (h *ConfigHash) Result() ([]common.ReturnResultLine, error) { + return nil, errors.ErrFetch +} diff --git a/config-parser/parsers/extra/config-hash_generated.go b/config-parser/parsers/extra/config-hash_generated.go new file mode 100644 index 00000000..5b00a1a5 --- /dev/null +++ b/config-parser/parsers/extra/config-hash_generated.go @@ -0,0 +1,83 @@ +// Code generated by go generate; DO NOT EDIT. +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package extra + +import ( + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +func (p *ConfigHash) GetParserName() string { + return p.Name +} + +func (p *ConfigHash) GetPreComments() ([]string, error) { + return p.preComments, nil +} + +func (p *ConfigHash) SetPreComments(preComments []string) { + p.preComments = preComments +} + +func (p *ConfigHash) GetOne(index int) (common.ParserData, error) { + if index > 0 { + return nil, errors.ErrFetch + } + if p.data == nil { + return nil, errors.ErrFetch + } + return p.data, nil +} + +func (p *ConfigHash) Delete(index int) error { + p.Init() + return nil +} + +func (p *ConfigHash) Insert(data common.ParserData, index int) error { + return p.Set(data, index) +} + +func (p *ConfigHash) Set(data common.ParserData, index int) error { + if data == nil { + p.Init() + return nil + } + switch newValue := data.(type) { + case *types.ConfigHash: + p.data = newValue + case types.ConfigHash: + p.data = &newValue + default: + return errors.ErrInvalidData + } + return nil +} + +func (p *ConfigHash) PreParse(line string, parts []string, preComments []string, comment string) (string, error) { + changeState, err := p.Parse(line, parts, comment) + if err == nil && preComments != nil { + p.preComments = append(p.preComments, preComments...) + } + return changeState, err +} + +func (p *ConfigHash) ResultAll() ([]common.ReturnResultLine, []string, error) { + res, err := p.Result() + return res, p.preComments, err +} diff --git a/config-parser/parsers/extra/config-version.go b/config-parser/parsers/extra/config-version.go new file mode 100644 index 00000000..395cdc42 --- /dev/null +++ b/config-parser/parsers/extra/config-version.go @@ -0,0 +1,85 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package extra + +import ( + "fmt" + "strconv" + "strings" + + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +type ConfigVersion struct { + Name string + data *types.ConfigVersion + preComments []string // comments that appear before the actual line +} + +func (p *ConfigVersion) Init() { + p.Name = "# _version" + p.data = nil +} + +func (p *ConfigVersion) Get(createIfNotExist bool) (common.ParserData, error) { + if p.data != nil { + return p.data, nil + } else if createIfNotExist { + p.data = &types.ConfigVersion{ + Value: 1, + } + return p.data, nil + } + return nil, fmt.Errorf("no data") +} + +// Parse see if we have version, since it is not haproxy keyword, it's in comments +func (p *ConfigVersion) Parse(line string, parts []string, comment string) (string, error) { + if strings.HasPrefix(comment, "_version") { + data := common.StringSplitIgnoreEmpty(comment, '=') + if len(data) < 2 { + return "", &errors.ParseError{Parser: "ConfigVersion", Line: line} + } + // version has been already set, first match wins + if p.data != nil { + return "", &errors.ParseError{Parser: "ConfigVersion", Line: line} + } + + if version, err := strconv.ParseInt(data[1], 10, 64); err == nil { + p.data = &types.ConfigVersion{ + Value: version, + } + } + return "", nil + } + return "", &errors.ParseError{Parser: "ConfigVersion", Line: line} +} + +func (p *ConfigVersion) Result() ([]common.ReturnResultLine, error) { + if p.data == nil { + return nil, errors.ErrFetch + } + + return []common.ReturnResultLine{ + { + Data: fmt.Sprintf("# _version=%d", p.data.Value), + Comment: "", + }, + }, nil +} diff --git a/config-parser/parsers/extra/config-version_generated.go b/config-parser/parsers/extra/config-version_generated.go new file mode 100644 index 00000000..0f043fa0 --- /dev/null +++ b/config-parser/parsers/extra/config-version_generated.go @@ -0,0 +1,83 @@ +// Code generated by go generate; DO NOT EDIT. +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package extra + +import ( + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +func (p *ConfigVersion) GetParserName() string { + return p.Name +} + +func (p *ConfigVersion) GetPreComments() ([]string, error) { + return p.preComments, nil +} + +func (p *ConfigVersion) SetPreComments(preComments []string) { + p.preComments = preComments +} + +func (p *ConfigVersion) GetOne(index int) (common.ParserData, error) { + if index > 0 { + return nil, errors.ErrFetch + } + if p.data == nil { + return nil, errors.ErrFetch + } + return p.data, nil +} + +func (p *ConfigVersion) Delete(index int) error { + p.Init() + return nil +} + +func (p *ConfigVersion) Insert(data common.ParserData, index int) error { + return p.Set(data, index) +} + +func (p *ConfigVersion) Set(data common.ParserData, index int) error { + if data == nil { + p.Init() + return nil + } + switch newValue := data.(type) { + case *types.ConfigVersion: + p.data = newValue + case types.ConfigVersion: + p.data = &newValue + default: + return errors.ErrInvalidData + } + return nil +} + +func (p *ConfigVersion) PreParse(line string, parts []string, preComments []string, comment string) (string, error) { + changeState, err := p.Parse(line, parts, comment) + if err == nil && preComments != nil { + p.preComments = append(p.preComments, preComments...) + } + return changeState, err +} + +func (p *ConfigVersion) ResultAll() ([]common.ReturnResultLine, []string, error) { + res, err := p.Result() + return res, p.preComments, err +} diff --git a/config-parser/parsers/extra/section.go b/config-parser/parsers/extra/section.go new file mode 100644 index 00000000..7ef2731c --- /dev/null +++ b/config-parser/parsers/extra/section.go @@ -0,0 +1,53 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package extra + +import ( + "fmt" + + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +type Section struct { + Name string + data *types.Section + preComments []string // comments that appear before the actual line +} + +func (s *Section) Init() { + s.data = &types.Section{} +} + +// Parse see if we have section name +func (s *Section) Parse(line string, parts []string, comment string) (string, error) { + if parts[0] == s.Name { + if len(parts) > 1 { + s.data.Name = parts[1] + } + if len(parts) > 3 && parts[2] == "from" { + s.data.FromDefaults = parts[3] + } + return s.Name, nil + } + return "", &errors.ParseError{Parser: "Section", Line: line} +} + +func (s *Section) Result() ([]common.ReturnResultLine, error) { + return nil, fmt.Errorf("not valid") +} diff --git a/config-parser/parsers/extra/section_generated.go b/config-parser/parsers/extra/section_generated.go new file mode 100644 index 00000000..07b06667 --- /dev/null +++ b/config-parser/parsers/extra/section_generated.go @@ -0,0 +1,94 @@ +// Code generated by go generate; DO NOT EDIT. +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package extra + +import ( + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +func (p *Section) GetParserName() string { + return p.Name +} + +func (p *Section) Get(createIfNotExist bool) (common.ParserData, error) { + if p.data == nil { + if createIfNotExist { + p.data = &types.Section{} + return p.data, nil + } + return nil, errors.ErrFetch + } + return p.data, nil +} + +func (p *Section) GetPreComments() ([]string, error) { + return p.preComments, nil +} + +func (p *Section) SetPreComments(preComments []string) { + p.preComments = preComments +} + +func (p *Section) GetOne(index int) (common.ParserData, error) { + if index > 0 { + return nil, errors.ErrFetch + } + if p.data == nil { + return nil, errors.ErrFetch + } + return p.data, nil +} + +func (p *Section) Delete(index int) error { + p.Init() + return nil +} + +func (p *Section) Insert(data common.ParserData, index int) error { + return p.Set(data, index) +} + +func (p *Section) Set(data common.ParserData, index int) error { + if data == nil { + p.Init() + return nil + } + switch newValue := data.(type) { + case *types.Section: + p.data = newValue + case types.Section: + p.data = &newValue + default: + return errors.ErrInvalidData + } + return nil +} + +func (p *Section) PreParse(line string, parts []string, preComments []string, comment string) (string, error) { + changeState, err := p.Parse(line, parts, comment) + if err == nil && preComments != nil { + p.preComments = append(p.preComments, preComments...) + } + return changeState, err +} + +func (p *Section) ResultAll() ([]common.ReturnResultLine, []string, error) { + res, err := p.Result() + return res, p.preComments, err +} diff --git a/config-parser/parsers/extra/unprocessed.go b/config-parser/parsers/extra/unprocessed.go new file mode 100644 index 00000000..894baedf --- /dev/null +++ b/config-parser/parsers/extra/unprocessed.go @@ -0,0 +1,57 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package extra + +import ( + "strings" + + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +type UnProcessed struct { + Name string + data []types.UnProcessed + preComments []string // comments that appear before the actual line +} + +func (u *UnProcessed) Init() { + u.Name = "" + u.data = []types.UnProcessed{} +} + +func (u *UnProcessed) Parse(line string, parts []string, comment string) (string, error) { + u.data = append(u.data, types.UnProcessed{ + Value: strings.TrimSpace(line), + }) + return "", nil +} + +func (u *UnProcessed) Result() ([]common.ReturnResultLine, error) { + if len(u.data) == 0 { + return nil, errors.ErrFetch + } + result := make([]common.ReturnResultLine, len(u.data)) + for index, d := range u.data { + result[index] = common.ReturnResultLine{ + Data: d.Value, + Comment: "", + } + } + return result, nil +} diff --git a/config-parser/parsers/extra/unprocessed_generated.go b/config-parser/parsers/extra/unprocessed_generated.go new file mode 100644 index 00000000..2ba0d687 --- /dev/null +++ b/config-parser/parsers/extra/unprocessed_generated.go @@ -0,0 +1,137 @@ +// Code generated by go generate; DO NOT EDIT. +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package extra + +import ( + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +func (p *UnProcessed) GetParserName() string { + return p.Name +} + +func (p *UnProcessed) Get(createIfNotExist bool) (common.ParserData, error) { + if len(p.data) == 0 && !createIfNotExist { + return nil, errors.ErrFetch + } + return p.data, nil +} + +func (p *UnProcessed) GetPreComments() ([]string, error) { + return p.preComments, nil +} + +func (p *UnProcessed) SetPreComments(preComments []string) { + p.preComments = preComments +} + +func (p *UnProcessed) GetOne(index int) (common.ParserData, error) { + if index < 0 || index >= len(p.data) { + return nil, errors.ErrFetch + } + return p.data[index], nil +} + +func (p *UnProcessed) Delete(index int) error { + if index < 0 || index >= len(p.data) { + return errors.ErrFetch + } + copy(p.data[index:], p.data[index+1:]) + p.data[len(p.data)-1] = types.UnProcessed{} + p.data = p.data[:len(p.data)-1] + return nil +} + +func (p *UnProcessed) Insert(data common.ParserData, index int) error { + if data == nil { + return errors.ErrInvalidData + } + switch newValue := data.(type) { + case []types.UnProcessed: + p.data = newValue + case *types.UnProcessed: + if index > -1 { + if index > len(p.data) { + return errors.ErrIndexOutOfRange + } + p.data = append(p.data, types.UnProcessed{}) + copy(p.data[index+1:], p.data[index:]) + p.data[index] = *newValue + } else { + p.data = append(p.data, *newValue) + } + case types.UnProcessed: + if index > -1 { + if index > len(p.data) { + return errors.ErrIndexOutOfRange + } + p.data = append(p.data, types.UnProcessed{}) + copy(p.data[index+1:], p.data[index:]) + p.data[index] = newValue + } else { + p.data = append(p.data, newValue) + } + default: + return errors.ErrInvalidData + } + return nil +} + +func (p *UnProcessed) Set(data common.ParserData, index int) error { + if data == nil { + p.Init() + return nil + } + switch newValue := data.(type) { + case []types.UnProcessed: + p.data = newValue + case *types.UnProcessed: + if index > -1 && index < len(p.data) { + p.data[index] = *newValue + } else if index == -1 { + p.data = append(p.data, *newValue) + } else { + return errors.ErrIndexOutOfRange + } + case types.UnProcessed: + if index > -1 && index < len(p.data) { + p.data[index] = newValue + } else if index == -1 { + p.data = append(p.data, newValue) + } else { + return errors.ErrIndexOutOfRange + } + default: + return errors.ErrInvalidData + } + return nil +} + +func (p *UnProcessed) PreParse(line string, parts []string, preComments []string, comment string) (string, error) { + changeState, err := p.Parse(line, parts, comment) + if err == nil && preComments != nil { + p.preComments = append(p.preComments, preComments...) + } + return changeState, err +} + +func (p *UnProcessed) ResultAll() ([]common.ReturnResultLine, []string, error) { + res, err := p.Result() + return res, p.preComments, err +} diff --git a/config-parser/parsers/filters/filter-cache.go b/config-parser/parsers/filters/filter-cache.go new file mode 100644 index 00000000..03f7d10e --- /dev/null +++ b/config-parser/parsers/filters/filter-cache.go @@ -0,0 +1,54 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package filters + +import ( + "fmt" + "strings" + + "github.com/haproxytech/client-native/v5/config-parser/common" +) + +type Cache struct { + Name string + Comment string +} + +func (f *Cache) Parse(parts []string, comment string) error { + if comment != "" { + f.Comment = comment + } + if len(parts) > 2 { + f.Name = parts[2] + } else { + return fmt.Errorf("no cache name") + } + return nil +} + +func (f *Cache) Result() common.ReturnResultLine { + var result strings.Builder + result.WriteString("filter cache") + if f.Name != "" { + result.WriteString(" ") + result.WriteString(f.Name) + } + return common.ReturnResultLine{ + Data: result.String(), + Comment: f.Comment, + } +} diff --git a/config-parser/parsers/filters/filter-compression.go b/config-parser/parsers/filters/filter-compression.go new file mode 100644 index 00000000..ae8d3ff3 --- /dev/null +++ b/config-parser/parsers/filters/filter-compression.go @@ -0,0 +1,49 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package filters + +import ( + "fmt" + "strings" + + "github.com/haproxytech/client-native/v5/config-parser/common" +) + +type Compression struct { + Enabled bool + Comment string +} + +func (f *Compression) Parse(parts []string, comment string) error { + if comment != "" { + f.Comment = comment + } + if len(parts) > 2 { + return fmt.Errorf("unexpected extra args: %s", strings.Join(parts[2:], " ")) + } + f.Enabled = true + return nil +} + +func (f *Compression) Result() common.ReturnResultLine { + var result strings.Builder + result.WriteString("filter compression") + return common.ReturnResultLine{ + Data: result.String(), + Comment: f.Comment, + } +} diff --git a/config-parser/parsers/filters/filter-fcgi-app.go b/config-parser/parsers/filters/filter-fcgi-app.go new file mode 100644 index 00000000..90cf79dc --- /dev/null +++ b/config-parser/parsers/filters/filter-fcgi-app.go @@ -0,0 +1,59 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package filters + +import ( + "fmt" + "strings" + + "github.com/haproxytech/client-native/v5/config-parser/common" +) + +type FcgiApp struct { + Comment string + Name string +} + +func (f *FcgiApp) Parse(parts []string, comment string) error { + f.Comment = comment + + switch len(parts) { + case 3: + f.Name = parts[2] + case 2: + return fmt.Errorf("no FastCGI application name") + default: + return fmt.Errorf("unsupported extra options: %s", strings.Join(parts[2:], " ")) + } + + return nil +} + +func (f *FcgiApp) Result() common.ReturnResultLine { + var result strings.Builder + result.WriteString("filter fcgi-app") + + if f.Name != "" { + result.WriteString(" ") + result.WriteString(f.Name) + } + + return common.ReturnResultLine{ + Data: result.String(), + Comment: f.Comment, + } +} diff --git a/config-parser/parsers/filters/filter-opentracing.go b/config-parser/parsers/filters/filter-opentracing.go new file mode 100644 index 00000000..12a5e20a --- /dev/null +++ b/config-parser/parsers/filters/filter-opentracing.go @@ -0,0 +1,81 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package filters + +import ( + "fmt" + "strings" + + "github.com/haproxytech/client-native/v5/config-parser/common" +) + +type Opentracing struct { + Comment string + ID string + Config string +} + +func (o *Opentracing) Parse(parts []string, comment string) error { + o.Comment = comment + + if len(parts) < 3 || len(parts)%2 == 1 { + return fmt.Errorf("missing required options") + } + + for index, part := range parts { + switch index { + case 0, 1: + continue + case 2, 4: + switch part { + case "id": + o.ID = parts[index+1] + case "config": + o.Config = parts[index+1] + default: + return fmt.Errorf("unsupported option: %s", part) + } + case 3, 5: // values, can be ignored + continue + default: + return fmt.Errorf("unexpected options: %s", strings.Join(parts[index:], " ")) + } + } + + return nil +} + +func (o *Opentracing) Result() common.ReturnResultLine { + var result strings.Builder + + result.WriteString("filter opentracing") + + if o.ID != "" { + result.WriteString(" id ") + result.WriteString(o.ID) + } + + if o.Config != "" { + result.WriteString(" config ") + result.WriteString(o.Config) + } + + return common.ReturnResultLine{ + Data: result.String(), + Comment: o.Comment, + } +} diff --git a/config-parser/parsers/filters/filter-spoe.go b/config-parser/parsers/filters/filter-spoe.go new file mode 100644 index 00000000..cfc26323 --- /dev/null +++ b/config-parser/parsers/filters/filter-spoe.go @@ -0,0 +1,75 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package filters + +import ( + "strings" + + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" +) + +type Spoe struct { // filter spoe [engine ] config + Engine string + Config string + Comment string +} + +func (f *Spoe) Parse(parts []string, comment string) error { + if comment != "" { + f.Comment = comment + } + index := 2 + for index < len(parts) { + switch parts[index] { + case "engine": + index++ + if index == len(parts) { + return errors.ErrInvalidData + } + f.Engine = parts[index] + case "config": + index++ + if index == len(parts) { + return errors.ErrInvalidData + } + f.Config = parts[index] + default: + return errors.ErrInvalidData + } + index++ + } + if f.Config == "" { + return errors.ErrInvalidData + } + return nil +} + +func (f *Spoe) Result() common.ReturnResultLine { + var result strings.Builder + result.WriteString("filter spoe") + if f.Engine != "" { + result.WriteString(" engine ") + result.WriteString(f.Engine) + } + result.WriteString(" config ") + result.WriteString(f.Config) + return common.ReturnResultLine{ + Data: result.String(), + Comment: f.Comment, + } +} diff --git a/config-parser/parsers/filters/filter-trace.go b/config-parser/parsers/filters/filter-trace.go new file mode 100644 index 00000000..e69de083 --- /dev/null +++ b/config-parser/parsers/filters/filter-trace.go @@ -0,0 +1,85 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package filters + +import ( + "strings" + + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" +) + +type Trace struct { // filter trace [name ] [random-parsing] [random-forwarding] [hexdump] + Name string + RandomParsing bool + RandomForwarding bool + Hexdump bool + Comment string +} + +func (f *Trace) Parse(parts []string, comment string) error { + // we have filter trace [name ] [random-parsing] [random-forwarding] [hexdump] + if comment != "" { + f.Comment = comment + } + if len(parts) < 2 { + return errors.ErrInvalidData + } + index := 2 + for index < len(parts) { + switch parts[index] { + case "name": + index++ + if index == len(parts) { + return errors.ErrInvalidData + } + f.Name = parts[index] + case "random-parsing": + f.RandomParsing = true + case "random-forwarding": + f.RandomForwarding = true + case "hexdump": + f.Hexdump = true + default: + return errors.ErrInvalidData + } + index++ + } + return nil +} + +func (f *Trace) Result() common.ReturnResultLine { + var result strings.Builder + result.WriteString("filter trace") + if f.Name != "" { + result.WriteString(" name ") + result.WriteString(f.Name) + } + if f.RandomParsing { + result.WriteString(" random-parsing") + } + if f.RandomForwarding { + result.WriteString(" random-forwarding") + } + if f.Hexdump { + result.WriteString(" hexdump") + } + return common.ReturnResultLine{ + Data: result.String(), + Comment: f.Comment, + } +} diff --git a/config-parser/parsers/filters/filter.go b/config-parser/parsers/filters/filter.go new file mode 100644 index 00000000..02916da3 --- /dev/null +++ b/config-parser/parsers/filters/filter.go @@ -0,0 +1,82 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package filters + +import ( + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +type Filters struct { + Name string + data []types.Filter + preComments []string // comments that appear before the actual line +} + +func (h *Filters) Init() { + h.data = []types.Filter{} + h.Name = "filter" +} + +func (h *Filters) ParseFilter(filter types.Filter, parts []string, comment string) error { + if err := filter.Parse(parts, ""); err != nil { + return &errors.ParseError{Parser: "FilterLines", Line: ""} + } + h.data = append(h.data, filter) + return nil +} + +func (h *Filters) Parse(line string, parts []string, comment string) (string, error) { + if len(parts) >= 2 && parts[0] == "filter" { + var err error + switch parts[1] { + case "trace": + err = h.ParseFilter(&Trace{}, parts, comment) + case "compression": + err = h.ParseFilter(&Compression{}, parts, comment) + case "cache": + err = h.ParseFilter(&Cache{}, parts, comment) + case "spoe": + err = h.ParseFilter(&Spoe{}, parts, comment) + case "fcgi-app": + err = h.ParseFilter(&FcgiApp{}, parts, comment) + case "opentracing": + err = h.ParseFilter(&Opentracing{}, parts, comment) + case "bwlim-in", "bwlim-out": + err = h.ParseFilter(&BandwidthLimit{}, parts, comment) + default: + return "", &errors.ParseError{Parser: "FilterLines", Line: line} + } + if err != nil { + return "", err + } + return "", nil + } + return "", &errors.ParseError{Parser: "FilterLines", Line: line} +} + +func (h *Filters) Result() ([]common.ReturnResultLine, error) { + if len(h.data) == 0 { + return nil, errors.ErrFetch + } + result := make([]common.ReturnResultLine, len(h.data)) + for index, req := range h.data { + result[index] = req.Result() + } + return result, nil +} diff --git a/config-parser/parsers/filters/filter_generated.go b/config-parser/parsers/filters/filter_generated.go new file mode 100644 index 00000000..a722cd9a --- /dev/null +++ b/config-parser/parsers/filters/filter_generated.go @@ -0,0 +1,137 @@ +// Code generated by go generate; DO NOT EDIT. +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package filters + +import ( + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +func (p *Filters) GetParserName() string { + return p.Name +} + +func (p *Filters) Get(createIfNotExist bool) (common.ParserData, error) { + if len(p.data) == 0 && !createIfNotExist { + return nil, errors.ErrFetch + } + return p.data, nil +} + +func (p *Filters) GetPreComments() ([]string, error) { + return p.preComments, nil +} + +func (p *Filters) SetPreComments(preComments []string) { + p.preComments = preComments +} + +func (p *Filters) GetOne(index int) (common.ParserData, error) { + if index < 0 || index >= len(p.data) { + return nil, errors.ErrFetch + } + return p.data[index], nil +} + +func (p *Filters) Delete(index int) error { + if index < 0 || index >= len(p.data) { + return errors.ErrFetch + } + copy(p.data[index:], p.data[index+1:]) + p.data[len(p.data)-1] = nil + p.data = p.data[:len(p.data)-1] + return nil +} + +func (p *Filters) Insert(data common.ParserData, index int) error { + if data == nil { + return errors.ErrInvalidData + } + switch newValue := data.(type) { + case []types.Filter: + p.data = newValue + case *types.Filter: + if index > -1 { + if index > len(p.data) { + return errors.ErrIndexOutOfRange + } + p.data = append(p.data, nil) + copy(p.data[index+1:], p.data[index:]) + p.data[index] = *newValue + } else { + p.data = append(p.data, *newValue) + } + case types.Filter: + if index > -1 { + if index > len(p.data) { + return errors.ErrIndexOutOfRange + } + p.data = append(p.data, nil) + copy(p.data[index+1:], p.data[index:]) + p.data[index] = newValue + } else { + p.data = append(p.data, newValue) + } + default: + return errors.ErrInvalidData + } + return nil +} + +func (p *Filters) Set(data common.ParserData, index int) error { + if data == nil { + p.Init() + return nil + } + switch newValue := data.(type) { + case []types.Filter: + p.data = newValue + case *types.Filter: + if index > -1 && index < len(p.data) { + p.data[index] = *newValue + } else if index == -1 { + p.data = append(p.data, *newValue) + } else { + return errors.ErrIndexOutOfRange + } + case types.Filter: + if index > -1 && index < len(p.data) { + p.data[index] = newValue + } else if index == -1 { + p.data = append(p.data, newValue) + } else { + return errors.ErrIndexOutOfRange + } + default: + return errors.ErrInvalidData + } + return nil +} + +func (p *Filters) PreParse(line string, parts []string, preComments []string, comment string) (string, error) { + changeState, err := p.Parse(line, parts, comment) + if err == nil && preComments != nil { + p.preComments = append(p.preComments, preComments...) + } + return changeState, err +} + +func (p *Filters) ResultAll() ([]common.ReturnResultLine, []string, error) { + res, err := p.Result() + return res, p.preComments, err +} diff --git a/config-parser/parsers/filters/filters-bwlim.go b/config-parser/parsers/filters/filters-bwlim.go new file mode 100644 index 00000000..cce61ccd --- /dev/null +++ b/config-parser/parsers/filters/filters-bwlim.go @@ -0,0 +1,133 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package filters + +import ( + "fmt" + "strings" + + "github.com/haproxytech/client-native/v5/config-parser/common" +) + +type BandwidthLimit struct { + Comment string + Attribute string + Name string + DefaultLimit string + DefaultPeriod string + Limit string + Key string + Table *string + MinSize *string +} + +func (b *BandwidthLimit) Parse(parts []string, comment string) error { + b.Comment = comment + + switch { + case len(parts) < 7 || len(parts[1:])%2 == 1: + return fmt.Errorf("missing required options") + case len(parts) > 11: + return fmt.Errorf("unsupported extra options") + } + + for index, part := range parts { + switch index { + case 1: + b.Attribute = part + case 2: + b.Name = part + case 3, 5, 7, 9: + if err := b.parsePart(parts, index); err != nil { + return err + } + case 0, 4, 6, 8, 10: // keyword or values, can be ignored + continue + default: + return fmt.Errorf("unexpected options: %s", strings.Join(parts[index:], " ")) + } + } + + switch { + case len(b.Limit) > 0 && len(b.Key) == 0: + return fmt.Errorf("missing required key options") + case len(b.Key) > 0 && len(b.Limit) == 0: + return fmt.Errorf("missing required key limit") + } + + return nil +} + +func (b *BandwidthLimit) parsePart(parts []string, index int) error { + part := parts[index] + switch part { + case "default-limit": + b.DefaultLimit = parts[index+1] + case "limit": + b.Limit = parts[index+1] + case "key": + b.Key = parts[index+1] + case "default-period": + b.DefaultPeriod = parts[index+1] + case "min-size": + v := parts[index+1] + b.MinSize = &v + case "table": + v := parts[index+1] + b.Table = &v + default: + return fmt.Errorf("unsupported option: %s", part) + } + + return nil +} + +func (b *BandwidthLimit) Result() common.ReturnResultLine { + var result strings.Builder + + result.WriteString("filter ") + result.WriteString(b.Attribute) + result.WriteString(" ") + result.WriteString(b.Name) + + if len(b.Key) > 0 && len(b.Limit) > 0 { + result.WriteString(" limit ") + result.WriteString(b.Limit) + result.WriteString(" key ") + result.WriteString(b.Key) + + if table := b.Table; table != nil { + result.WriteString(" table ") + result.WriteString(*table) + } + } else { + result.WriteString(" default-limit ") + result.WriteString(b.DefaultLimit) + result.WriteString(" default-period ") + result.WriteString(b.DefaultPeriod) + } + + if b.MinSize != nil { + result.WriteString(" min-size ") + result.WriteString(*b.MinSize) + } + + return common.ReturnResultLine{ + Data: result.String(), + Comment: b.Comment, + } +} diff --git a/config-parser/parsers/force-persist.go b/config-parser/parsers/force-persist.go new file mode 100644 index 00000000..f7314615 --- /dev/null +++ b/config-parser/parsers/force-persist.go @@ -0,0 +1,61 @@ +/* +Copyright 2022 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package parsers + +import ( + "fmt" + + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +type ForcePersist struct { + data []types.ForcePersist + preComments []string // comments that appear before the actual line +} + +func (m *ForcePersist) parse(line string, parts []string, comment string) (*types.ForcePersist, error) { + if len(parts) != 3 { + return nil, &errors.ParseError{Parser: "ForcePersist", Line: line} + } + if parts[0] == "force-persist" { + if parts[1] != "if" && parts[1] != "unless" { + return nil, &errors.ParseError{Parser: "ForcePersist", Line: line} + } + data := &types.ForcePersist{ + Cond: parts[1], + CondTest: parts[2], + Comment: comment, + } + return data, nil + } + return nil, &errors.ParseError{Parser: "ForcePersist", Line: line} +} + +func (m *ForcePersist) Result() ([]common.ReturnResultLine, error) { + if len(m.data) == 0 { + return nil, errors.ErrFetch + } + result := make([]common.ReturnResultLine, len(m.data)) + for i := range m.data { + result[i] = common.ReturnResultLine{ + Data: fmt.Sprintf("force-persist %s %s", m.data[i].Cond, m.data[i].CondTest), + Comment: m.data[i].Comment, + } + } + return result, nil +} diff --git a/config-parser/parsers/force-persist_generated.go b/config-parser/parsers/force-persist_generated.go new file mode 100644 index 00000000..444499cb --- /dev/null +++ b/config-parser/parsers/force-persist_generated.go @@ -0,0 +1,157 @@ +// Code generated by go generate; DO NOT EDIT. +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package parsers + +import ( + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +func (p *ForcePersist) Init() { + p.data = []types.ForcePersist{} + p.preComments = []string{} +} + +func (p *ForcePersist) GetParserName() string { + return "force-persist" +} + +func (p *ForcePersist) Get(createIfNotExist bool) (common.ParserData, error) { + if len(p.data) == 0 && !createIfNotExist { + return nil, errors.ErrFetch + } + return p.data, nil +} + +func (p *ForcePersist) GetPreComments() ([]string, error) { + return p.preComments, nil +} + +func (p *ForcePersist) SetPreComments(preComments []string) { + p.preComments = preComments +} + +func (p *ForcePersist) GetOne(index int) (common.ParserData, error) { + if index < 0 || index >= len(p.data) { + return nil, errors.ErrFetch + } + return p.data[index], nil +} + +func (p *ForcePersist) Delete(index int) error { + if index < 0 || index >= len(p.data) { + return errors.ErrFetch + } + copy(p.data[index:], p.data[index+1:]) + p.data[len(p.data)-1] = types.ForcePersist{} + p.data = p.data[:len(p.data)-1] + return nil +} + +func (p *ForcePersist) Insert(data common.ParserData, index int) error { + if data == nil { + return errors.ErrInvalidData + } + switch newValue := data.(type) { + case []types.ForcePersist: + p.data = newValue + case *types.ForcePersist: + if index > -1 { + if index > len(p.data) { + return errors.ErrIndexOutOfRange + } + p.data = append(p.data, types.ForcePersist{}) + copy(p.data[index+1:], p.data[index:]) + p.data[index] = *newValue + } else { + p.data = append(p.data, *newValue) + } + case types.ForcePersist: + if index > -1 { + if index > len(p.data) { + return errors.ErrIndexOutOfRange + } + p.data = append(p.data, types.ForcePersist{}) + copy(p.data[index+1:], p.data[index:]) + p.data[index] = newValue + } else { + p.data = append(p.data, newValue) + } + default: + return errors.ErrInvalidData + } + return nil +} + +func (p *ForcePersist) Set(data common.ParserData, index int) error { + if data == nil { + p.Init() + return nil + } + switch newValue := data.(type) { + case []types.ForcePersist: + p.data = newValue + case *types.ForcePersist: + if index > -1 && index < len(p.data) { + p.data[index] = *newValue + } else if index == -1 { + p.data = append(p.data, *newValue) + } else { + return errors.ErrIndexOutOfRange + } + case types.ForcePersist: + if index > -1 && index < len(p.data) { + p.data[index] = newValue + } else if index == -1 { + p.data = append(p.data, newValue) + } else { + return errors.ErrIndexOutOfRange + } + default: + return errors.ErrInvalidData + } + return nil +} + +func (p *ForcePersist) PreParse(line string, parts []string, preComments []string, comment string) (string, error) { + changeState, err := p.Parse(line, parts, comment) + if err == nil && preComments != nil { + p.preComments = append(p.preComments, preComments...) + } + return changeState, err +} + +func (p *ForcePersist) Parse(line string, parts []string, comment string) (string, error) { + if parts[0] == "force-persist" { + data, err := p.parse(line, parts, comment) + if err != nil { + if _, ok := err.(*errors.ParseError); ok { + return "", err + } + return "", &errors.ParseError{Parser: "ForcePersist", Line: line} + } + p.data = append(p.data, *data) + return "", nil + } + return "", &errors.ParseError{Parser: "ForcePersist", Line: line} +} + +func (p *ForcePersist) ResultAll() ([]common.ReturnResultLine, []string, error) { + res, err := p.Result() + return res, p.preComments, err +} diff --git a/config-parser/parsers/group.go b/config-parser/parsers/group.go new file mode 100644 index 00000000..e41e537d --- /dev/null +++ b/config-parser/parsers/group.go @@ -0,0 +1,74 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package parsers + +import ( + "fmt" + "strings" + + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +type Group struct { + data []types.Group + preComments []string // comments that appear before the actual line +} + +func (l *Group) parse(line string, parts []string, comment string) (*types.Group, error) { + if len(parts) >= 2 { + group := &types.Group{ + Name: parts[1], + Comment: comment, + } + if len(parts) > 3 && parts[2] == "users" { + group.Users = common.StringSplitIgnoreEmpty(parts[3], ',') + } + return group, nil + } + return nil, &errors.ParseError{Parser: "Group", Line: line} +} + +func (l *Group) Result() ([]common.ReturnResultLine, error) { + if len(l.data) == 0 { + return nil, errors.ErrFetch + } + result := make([]common.ReturnResultLine, len(l.data)) + for index, group := range l.data { + users := "" + if len(group.Users) > 0 { + var s strings.Builder + s.WriteString(" users ") + first := true + for _, user := range group.Users { + if !first { + s.WriteString(",") + } else { + first = false + } + s.WriteString(user) + } + users = s.String() + } + result[index] = common.ReturnResultLine{ + Data: fmt.Sprintf("group %s%s", group.Name, users), + Comment: group.Comment, + } + } + return result, nil +} diff --git a/config-parser/parsers/group_generated.go b/config-parser/parsers/group_generated.go new file mode 100644 index 00000000..2fce894d --- /dev/null +++ b/config-parser/parsers/group_generated.go @@ -0,0 +1,157 @@ +// Code generated by go generate; DO NOT EDIT. +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package parsers + +import ( + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +func (p *Group) Init() { + p.data = []types.Group{} + p.preComments = []string{} +} + +func (p *Group) GetParserName() string { + return "group" +} + +func (p *Group) Get(createIfNotExist bool) (common.ParserData, error) { + if len(p.data) == 0 && !createIfNotExist { + return nil, errors.ErrFetch + } + return p.data, nil +} + +func (p *Group) GetPreComments() ([]string, error) { + return p.preComments, nil +} + +func (p *Group) SetPreComments(preComments []string) { + p.preComments = preComments +} + +func (p *Group) GetOne(index int) (common.ParserData, error) { + if index < 0 || index >= len(p.data) { + return nil, errors.ErrFetch + } + return p.data[index], nil +} + +func (p *Group) Delete(index int) error { + if index < 0 || index >= len(p.data) { + return errors.ErrFetch + } + copy(p.data[index:], p.data[index+1:]) + p.data[len(p.data)-1] = types.Group{} + p.data = p.data[:len(p.data)-1] + return nil +} + +func (p *Group) Insert(data common.ParserData, index int) error { + if data == nil { + return errors.ErrInvalidData + } + switch newValue := data.(type) { + case []types.Group: + p.data = newValue + case *types.Group: + if index > -1 { + if index > len(p.data) { + return errors.ErrIndexOutOfRange + } + p.data = append(p.data, types.Group{}) + copy(p.data[index+1:], p.data[index:]) + p.data[index] = *newValue + } else { + p.data = append(p.data, *newValue) + } + case types.Group: + if index > -1 { + if index > len(p.data) { + return errors.ErrIndexOutOfRange + } + p.data = append(p.data, types.Group{}) + copy(p.data[index+1:], p.data[index:]) + p.data[index] = newValue + } else { + p.data = append(p.data, newValue) + } + default: + return errors.ErrInvalidData + } + return nil +} + +func (p *Group) Set(data common.ParserData, index int) error { + if data == nil { + p.Init() + return nil + } + switch newValue := data.(type) { + case []types.Group: + p.data = newValue + case *types.Group: + if index > -1 && index < len(p.data) { + p.data[index] = *newValue + } else if index == -1 { + p.data = append(p.data, *newValue) + } else { + return errors.ErrIndexOutOfRange + } + case types.Group: + if index > -1 && index < len(p.data) { + p.data[index] = newValue + } else if index == -1 { + p.data = append(p.data, newValue) + } else { + return errors.ErrIndexOutOfRange + } + default: + return errors.ErrInvalidData + } + return nil +} + +func (p *Group) PreParse(line string, parts []string, preComments []string, comment string) (string, error) { + changeState, err := p.Parse(line, parts, comment) + if err == nil && preComments != nil { + p.preComments = append(p.preComments, preComments...) + } + return changeState, err +} + +func (p *Group) Parse(line string, parts []string, comment string) (string, error) { + if parts[0] == "group" { + data, err := p.parse(line, parts, comment) + if err != nil { + if _, ok := err.(*errors.ParseError); ok { + return "", err + } + return "", &errors.ParseError{Parser: "Group", Line: line} + } + p.data = append(p.data, *data) + return "", nil + } + return "", &errors.ParseError{Parser: "Group", Line: line} +} + +func (p *Group) ResultAll() ([]common.ReturnResultLine, []string, error) { + res, err := p.Result() + return res, p.preComments, err +} diff --git a/config-parser/parsers/h1-case-adjust.go b/config-parser/parsers/h1-case-adjust.go new file mode 100644 index 00000000..7e0c00cf --- /dev/null +++ b/config-parser/parsers/h1-case-adjust.go @@ -0,0 +1,57 @@ +/* +Copyright 2022 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package parsers + +import ( + "fmt" + + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +type H1CaseAdjust struct { + data []types.H1CaseAdjust + preComments []string // comments that appear before the actual line +} + +func (ca *H1CaseAdjust) parse(line string, parts []string, comment string) (*types.H1CaseAdjust, error) { + if len(parts) != 3 { + return nil, &errors.ParseError{Parser: "H1CaseAdjust", Line: line, Message: "Parse error"} + } + + h1CaseAdjust := &types.H1CaseAdjust{ + From: parts[1], + To: parts[2], + Comment: comment, + } + return h1CaseAdjust, nil +} + +func (ca *H1CaseAdjust) Result() ([]common.ReturnResultLine, error) { + if len(ca.data) == 0 { + return nil, errors.ErrFetch + } + result := make([]common.ReturnResultLine, len(ca.data)) + for index, h1CaseAdjust := range ca.data { + result[index] = common.ReturnResultLine{ + Data: fmt.Sprintf("h1-case-adjust %s %s", h1CaseAdjust.From, h1CaseAdjust.To), + Comment: h1CaseAdjust.Comment, + } + } + return result, nil +} diff --git a/config-parser/parsers/h1-case-adjust_generated.go b/config-parser/parsers/h1-case-adjust_generated.go new file mode 100644 index 00000000..cbbbbfa8 --- /dev/null +++ b/config-parser/parsers/h1-case-adjust_generated.go @@ -0,0 +1,157 @@ +// Code generated by go generate; DO NOT EDIT. +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package parsers + +import ( + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +func (p *H1CaseAdjust) Init() { + p.data = []types.H1CaseAdjust{} + p.preComments = []string{} +} + +func (p *H1CaseAdjust) GetParserName() string { + return "h1-case-adjust" +} + +func (p *H1CaseAdjust) Get(createIfNotExist bool) (common.ParserData, error) { + if len(p.data) == 0 && !createIfNotExist { + return nil, errors.ErrFetch + } + return p.data, nil +} + +func (p *H1CaseAdjust) GetPreComments() ([]string, error) { + return p.preComments, nil +} + +func (p *H1CaseAdjust) SetPreComments(preComments []string) { + p.preComments = preComments +} + +func (p *H1CaseAdjust) GetOne(index int) (common.ParserData, error) { + if index < 0 || index >= len(p.data) { + return nil, errors.ErrFetch + } + return p.data[index], nil +} + +func (p *H1CaseAdjust) Delete(index int) error { + if index < 0 || index >= len(p.data) { + return errors.ErrFetch + } + copy(p.data[index:], p.data[index+1:]) + p.data[len(p.data)-1] = types.H1CaseAdjust{} + p.data = p.data[:len(p.data)-1] + return nil +} + +func (p *H1CaseAdjust) Insert(data common.ParserData, index int) error { + if data == nil { + return errors.ErrInvalidData + } + switch newValue := data.(type) { + case []types.H1CaseAdjust: + p.data = newValue + case *types.H1CaseAdjust: + if index > -1 { + if index > len(p.data) { + return errors.ErrIndexOutOfRange + } + p.data = append(p.data, types.H1CaseAdjust{}) + copy(p.data[index+1:], p.data[index:]) + p.data[index] = *newValue + } else { + p.data = append(p.data, *newValue) + } + case types.H1CaseAdjust: + if index > -1 { + if index > len(p.data) { + return errors.ErrIndexOutOfRange + } + p.data = append(p.data, types.H1CaseAdjust{}) + copy(p.data[index+1:], p.data[index:]) + p.data[index] = newValue + } else { + p.data = append(p.data, newValue) + } + default: + return errors.ErrInvalidData + } + return nil +} + +func (p *H1CaseAdjust) Set(data common.ParserData, index int) error { + if data == nil { + p.Init() + return nil + } + switch newValue := data.(type) { + case []types.H1CaseAdjust: + p.data = newValue + case *types.H1CaseAdjust: + if index > -1 && index < len(p.data) { + p.data[index] = *newValue + } else if index == -1 { + p.data = append(p.data, *newValue) + } else { + return errors.ErrIndexOutOfRange + } + case types.H1CaseAdjust: + if index > -1 && index < len(p.data) { + p.data[index] = newValue + } else if index == -1 { + p.data = append(p.data, newValue) + } else { + return errors.ErrIndexOutOfRange + } + default: + return errors.ErrInvalidData + } + return nil +} + +func (p *H1CaseAdjust) PreParse(line string, parts []string, preComments []string, comment string) (string, error) { + changeState, err := p.Parse(line, parts, comment) + if err == nil && preComments != nil { + p.preComments = append(p.preComments, preComments...) + } + return changeState, err +} + +func (p *H1CaseAdjust) Parse(line string, parts []string, comment string) (string, error) { + if parts[0] == "h1-case-adjust" { + data, err := p.parse(line, parts, comment) + if err != nil { + if _, ok := err.(*errors.ParseError); ok { + return "", err + } + return "", &errors.ParseError{Parser: "H1CaseAdjust", Line: line} + } + p.data = append(p.data, *data) + return "", nil + } + return "", &errors.ParseError{Parser: "H1CaseAdjust", Line: line} +} + +func (p *H1CaseAdjust) ResultAll() ([]common.ReturnResultLine, []string, error) { + res, err := p.Result() + return res, p.preComments, err +} diff --git a/config-parser/parsers/hash-type.go b/config-parser/parsers/hash-type.go new file mode 100644 index 00000000..f379a853 --- /dev/null +++ b/config-parser/parsers/hash-type.go @@ -0,0 +1,82 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package parsers + +import ( + "strings" + + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +type HashType struct { + data *types.HashType + preComments []string // comments that appear before the actual line +} + +func (p *HashType) Parse(line string, parts []string, comment string) (string, error) { + if parts[0] == "hash-type" { + if len(parts) < 2 { + return "", &errors.ParseError{Parser: "HashType", Line: line, Message: "Parse error"} + } + data := types.HashType{ + Comment: comment, + } + index := 1 + for ; index < len(parts); index++ { + switch parts[index] { + case "map-based", "consistent": + data.Method = parts[index] + case "sdbm", "djb2", "wt6", "crc32", "none": + data.Function = parts[index] + case "avalanche": + data.Modifier = parts[index] + default: + return "", &errors.ParseError{Parser: "HashType", Line: line, Message: "Parse error"} + } + } + p.data = &data + return "", nil + } + return "", &errors.ParseError{Parser: "HashType", Line: line} +} + +func (p *HashType) Result() ([]common.ReturnResultLine, error) { + if p.data == nil { + return nil, errors.ErrFetch + } + var sb strings.Builder + sb.WriteString("hash-type") + if p.data.Method != "" { + sb.WriteString(" ") + sb.WriteString(p.data.Method) + } + if p.data.Function != "" { + sb.WriteString(" ") + sb.WriteString(p.data.Function) + } + if p.data.Modifier != "" { + sb.WriteString(" ") + sb.WriteString(p.data.Modifier) + } + return []common.ReturnResultLine{ + { + Data: sb.String(), + Comment: p.data.Comment, + }, + }, nil +} diff --git a/config-parser/parsers/hash-type_generated.go b/config-parser/parsers/hash-type_generated.go new file mode 100644 index 00000000..9d1b050d --- /dev/null +++ b/config-parser/parsers/hash-type_generated.go @@ -0,0 +1,99 @@ +// Code generated by go generate; DO NOT EDIT. +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package parsers + +import ( + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +func (p *HashType) Init() { + p.data = nil + p.preComments = []string{} +} + +func (p *HashType) GetParserName() string { + return "hash-type" +} + +func (p *HashType) Get(createIfNotExist bool) (common.ParserData, error) { + if p.data == nil { + if createIfNotExist { + p.data = &types.HashType{} + return p.data, nil + } + return nil, errors.ErrFetch + } + return p.data, nil +} + +func (p *HashType) GetPreComments() ([]string, error) { + return p.preComments, nil +} + +func (p *HashType) SetPreComments(preComments []string) { + p.preComments = preComments +} + +func (p *HashType) GetOne(index int) (common.ParserData, error) { + if index > 0 { + return nil, errors.ErrFetch + } + if p.data == nil { + return nil, errors.ErrFetch + } + return p.data, nil +} + +func (p *HashType) Delete(index int) error { + p.Init() + return nil +} + +func (p *HashType) Insert(data common.ParserData, index int) error { + return p.Set(data, index) +} + +func (p *HashType) Set(data common.ParserData, index int) error { + if data == nil { + p.Init() + return nil + } + switch newValue := data.(type) { + case *types.HashType: + p.data = newValue + case types.HashType: + p.data = &newValue + default: + return errors.ErrInvalidData + } + return nil +} + +func (p *HashType) PreParse(line string, parts []string, preComments []string, comment string) (string, error) { + changeState, err := p.Parse(line, parts, comment) + if err == nil && preComments != nil { + p.preComments = append(p.preComments, preComments...) + } + return changeState, err +} + +func (p *HashType) ResultAll() ([]common.ReturnResultLine, []string, error) { + res, err := p.Result() + return res, p.preComments, err +} diff --git a/config-parser/parsers/http-check.go b/config-parser/parsers/http-check.go new file mode 100644 index 00000000..96653ed4 --- /dev/null +++ b/config-parser/parsers/http-check.go @@ -0,0 +1,89 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package parsers + +import ( + "strings" + + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +type HTTPCheckV2 struct { + data []types.HTTPCheckV2 + preComments []string // comments that appear before the actual line +} + +func (h *HTTPCheckV2) parse(line string, parts []string, comment string) (*types.HTTPCheckV2, error) { + if len(parts) < 2 { + return nil, &errors.ParseError{Parser: "HttpCheck", Line: line} + } + + hc := &types.HTTPCheckV2{ + Comment: comment, + Type: parts[1], + } + if len(parts) == 2 { + return hc, nil + } + + if len(parts) >= 3 { + if parts[2] == "!" { + hc.ExclamationMark = true + hc.Match = parts[3] + hc.Pattern = strings.Join(parts[4:], " ") + return hc, nil + } + hc.Match = parts[2] + hc.Pattern = strings.Join(parts[3:], " ") + return hc, nil + } + return nil, &errors.ParseError{Parser: "HttpCheck", Line: line} +} + +func (h *HTTPCheckV2) Result() ([]common.ReturnResultLine, error) { + if len(h.data) == 0 { + return nil, errors.ErrFetch + } + + result := make([]common.ReturnResultLine, len(h.data)) + for index, c := range h.data { + var sb strings.Builder + sb.WriteString("http-check") + if c.Type != "" { + sb.WriteString(" ") + sb.WriteString(c.Type) + } + if c.ExclamationMark { + sb.WriteString(" !") + } + if c.Match != "" { + sb.WriteString(" ") + sb.WriteString(c.Match) + } + if c.Pattern != "" { + sb.WriteString(" ") + sb.WriteString(c.Pattern) + } + result[index] = common.ReturnResultLine{ + Data: sb.String(), + Comment: c.Comment, + } + } + return result, nil +} diff --git a/config-parser/parsers/http-check_generated.go b/config-parser/parsers/http-check_generated.go new file mode 100644 index 00000000..f7cd6688 --- /dev/null +++ b/config-parser/parsers/http-check_generated.go @@ -0,0 +1,157 @@ +// Code generated by go generate; DO NOT EDIT. +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package parsers + +import ( + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +func (p *HTTPCheckV2) Init() { + p.data = []types.HTTPCheckV2{} + p.preComments = []string{} +} + +func (p *HTTPCheckV2) GetParserName() string { + return "http-check" +} + +func (p *HTTPCheckV2) Get(createIfNotExist bool) (common.ParserData, error) { + if len(p.data) == 0 && !createIfNotExist { + return nil, errors.ErrFetch + } + return p.data, nil +} + +func (p *HTTPCheckV2) GetPreComments() ([]string, error) { + return p.preComments, nil +} + +func (p *HTTPCheckV2) SetPreComments(preComments []string) { + p.preComments = preComments +} + +func (p *HTTPCheckV2) GetOne(index int) (common.ParserData, error) { + if index < 0 || index >= len(p.data) { + return nil, errors.ErrFetch + } + return p.data[index], nil +} + +func (p *HTTPCheckV2) Delete(index int) error { + if index < 0 || index >= len(p.data) { + return errors.ErrFetch + } + copy(p.data[index:], p.data[index+1:]) + p.data[len(p.data)-1] = types.HTTPCheckV2{} + p.data = p.data[:len(p.data)-1] + return nil +} + +func (p *HTTPCheckV2) Insert(data common.ParserData, index int) error { + if data == nil { + return errors.ErrInvalidData + } + switch newValue := data.(type) { + case []types.HTTPCheckV2: + p.data = newValue + case *types.HTTPCheckV2: + if index > -1 { + if index > len(p.data) { + return errors.ErrIndexOutOfRange + } + p.data = append(p.data, types.HTTPCheckV2{}) + copy(p.data[index+1:], p.data[index:]) + p.data[index] = *newValue + } else { + p.data = append(p.data, *newValue) + } + case types.HTTPCheckV2: + if index > -1 { + if index > len(p.data) { + return errors.ErrIndexOutOfRange + } + p.data = append(p.data, types.HTTPCheckV2{}) + copy(p.data[index+1:], p.data[index:]) + p.data[index] = newValue + } else { + p.data = append(p.data, newValue) + } + default: + return errors.ErrInvalidData + } + return nil +} + +func (p *HTTPCheckV2) Set(data common.ParserData, index int) error { + if data == nil { + p.Init() + return nil + } + switch newValue := data.(type) { + case []types.HTTPCheckV2: + p.data = newValue + case *types.HTTPCheckV2: + if index > -1 && index < len(p.data) { + p.data[index] = *newValue + } else if index == -1 { + p.data = append(p.data, *newValue) + } else { + return errors.ErrIndexOutOfRange + } + case types.HTTPCheckV2: + if index > -1 && index < len(p.data) { + p.data[index] = newValue + } else if index == -1 { + p.data = append(p.data, newValue) + } else { + return errors.ErrIndexOutOfRange + } + default: + return errors.ErrInvalidData + } + return nil +} + +func (p *HTTPCheckV2) PreParse(line string, parts []string, preComments []string, comment string) (string, error) { + changeState, err := p.Parse(line, parts, comment) + if err == nil && preComments != nil { + p.preComments = append(p.preComments, preComments...) + } + return changeState, err +} + +func (p *HTTPCheckV2) Parse(line string, parts []string, comment string) (string, error) { + if parts[0] == "http-check" { + data, err := p.parse(line, parts, comment) + if err != nil { + if _, ok := err.(*errors.ParseError); ok { + return "", err + } + return "", &errors.ParseError{Parser: "HTTPCheckV2", Line: line} + } + p.data = append(p.data, *data) + return "", nil + } + return "", &errors.ParseError{Parser: "HTTPCheckV2", Line: line} +} + +func (p *HTTPCheckV2) ResultAll() ([]common.ReturnResultLine, []string, error) { + res, err := p.Result() + return res, p.preComments, err +} diff --git a/config-parser/parsers/http-reuse.go b/config-parser/parsers/http-reuse.go new file mode 100644 index 00000000..c0a5e557 --- /dev/null +++ b/config-parser/parsers/http-reuse.go @@ -0,0 +1,55 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package parsers + +import ( + "fmt" + + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +type HTTPReuse struct { + data *types.HTTPReuse + preComments []string // comments that appear before the actual line +} + +func (p *HTTPReuse) Parse(line string, parts []string, comment string) (string, error) { + if parts[0] == "http-reuse" { + switch parts[1] { + case "aggressive", "always", "never", "safe": + p.data = &types.HTTPReuse{ShareType: parts[1], Comment: comment} + return "", nil + default: + return "", &errors.ParseError{Parser: "HTTPReuse", Line: line} + } + } + return "", &errors.ParseError{Parser: "HTTPReuse", Line: line} +} + +func (p *HTTPReuse) Result() ([]common.ReturnResultLine, error) { + if p.data == nil { + return nil, errors.ErrFetch + } + return []common.ReturnResultLine{ + { + Data: fmt.Sprintf("http-reuse %s", p.data.ShareType), + Comment: p.data.Comment, + }, + }, nil +} diff --git a/config-parser/parsers/http-reuse_generated.go b/config-parser/parsers/http-reuse_generated.go new file mode 100644 index 00000000..b0063612 --- /dev/null +++ b/config-parser/parsers/http-reuse_generated.go @@ -0,0 +1,99 @@ +// Code generated by go generate; DO NOT EDIT. +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package parsers + +import ( + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +func (p *HTTPReuse) Init() { + p.data = nil + p.preComments = []string{} +} + +func (p *HTTPReuse) GetParserName() string { + return "http-reuse" +} + +func (p *HTTPReuse) Get(createIfNotExist bool) (common.ParserData, error) { + if p.data == nil { + if createIfNotExist { + p.data = &types.HTTPReuse{} + return p.data, nil + } + return nil, errors.ErrFetch + } + return p.data, nil +} + +func (p *HTTPReuse) GetPreComments() ([]string, error) { + return p.preComments, nil +} + +func (p *HTTPReuse) SetPreComments(preComments []string) { + p.preComments = preComments +} + +func (p *HTTPReuse) GetOne(index int) (common.ParserData, error) { + if index > 0 { + return nil, errors.ErrFetch + } + if p.data == nil { + return nil, errors.ErrFetch + } + return p.data, nil +} + +func (p *HTTPReuse) Delete(index int) error { + p.Init() + return nil +} + +func (p *HTTPReuse) Insert(data common.ParserData, index int) error { + return p.Set(data, index) +} + +func (p *HTTPReuse) Set(data common.ParserData, index int) error { + if data == nil { + p.Init() + return nil + } + switch newValue := data.(type) { + case *types.HTTPReuse: + p.data = newValue + case types.HTTPReuse: + p.data = &newValue + default: + return errors.ErrInvalidData + } + return nil +} + +func (p *HTTPReuse) PreParse(line string, parts []string, preComments []string, comment string) (string, error) { + changeState, err := p.Parse(line, parts, comment) + if err == nil && preComments != nil { + p.preComments = append(p.preComments, preComments...) + } + return changeState, err +} + +func (p *HTTPReuse) ResultAll() ([]common.ReturnResultLine, []string, error) { + res, err := p.Result() + return res, p.preComments, err +} diff --git a/config-parser/parsers/http-send-name-header.go b/config-parser/parsers/http-send-name-header.go new file mode 100644 index 00000000..b866a38c --- /dev/null +++ b/config-parser/parsers/http-send-name-header.go @@ -0,0 +1,58 @@ +/* +Copyright 2022 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package parsers + +import ( + "strings" + + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +type HTTPSendNameHeader struct { + data *types.HTTPSendNameHeader + preComments []string // comments that appear before the actual line +} + +func (m *HTTPSendNameHeader) Parse(line string, parts []string, comment string) (string, error) { + if parts[0] != "http-send-name-header" { + return "", &errors.ParseError{Parser: "HTTPSendNameHeader", Line: line} + } + m.data = &types.HTTPSendNameHeader{} + if len(parts) > 1 { + m.data.Name = parts[1] + } + return "", nil +} + +func (m *HTTPSendNameHeader) Result() ([]common.ReturnResultLine, error) { + if m.data == nil { + return nil, errors.ErrFetch + } + var sb strings.Builder + sb.WriteString("http-send-name-header") + if m.data.Name != "" { + sb.WriteString(" ") + sb.WriteString(m.data.Name) + } + return []common.ReturnResultLine{ + { + Data: sb.String(), + Comment: m.data.Comment, + }, + }, nil +} diff --git a/config-parser/parsers/http-send-name-header_generated.go b/config-parser/parsers/http-send-name-header_generated.go new file mode 100644 index 00000000..02689cbc --- /dev/null +++ b/config-parser/parsers/http-send-name-header_generated.go @@ -0,0 +1,99 @@ +// Code generated by go generate; DO NOT EDIT. +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package parsers + +import ( + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +func (p *HTTPSendNameHeader) Init() { + p.data = nil + p.preComments = []string{} +} + +func (p *HTTPSendNameHeader) GetParserName() string { + return "http-send-name-header" +} + +func (p *HTTPSendNameHeader) Get(createIfNotExist bool) (common.ParserData, error) { + if p.data == nil { + if createIfNotExist { + p.data = &types.HTTPSendNameHeader{} + return p.data, nil + } + return nil, errors.ErrFetch + } + return p.data, nil +} + +func (p *HTTPSendNameHeader) GetPreComments() ([]string, error) { + return p.preComments, nil +} + +func (p *HTTPSendNameHeader) SetPreComments(preComments []string) { + p.preComments = preComments +} + +func (p *HTTPSendNameHeader) GetOne(index int) (common.ParserData, error) { + if index > 0 { + return nil, errors.ErrFetch + } + if p.data == nil { + return nil, errors.ErrFetch + } + return p.data, nil +} + +func (p *HTTPSendNameHeader) Delete(index int) error { + p.Init() + return nil +} + +func (p *HTTPSendNameHeader) Insert(data common.ParserData, index int) error { + return p.Set(data, index) +} + +func (p *HTTPSendNameHeader) Set(data common.ParserData, index int) error { + if data == nil { + p.Init() + return nil + } + switch newValue := data.(type) { + case *types.HTTPSendNameHeader: + p.data = newValue + case types.HTTPSendNameHeader: + p.data = &newValue + default: + return errors.ErrInvalidData + } + return nil +} + +func (p *HTTPSendNameHeader) PreParse(line string, parts []string, preComments []string, comment string) (string, error) { + changeState, err := p.Parse(line, parts, comment) + if err == nil && preComments != nil { + p.preComments = append(p.preComments, preComments...) + } + return changeState, err +} + +func (p *HTTPSendNameHeader) ResultAll() ([]common.ReturnResultLine, []string, error) { + res, err := p.Result() + return res, p.preComments, err +} diff --git a/config-parser/parsers/http/actions/add-acl.go b/config-parser/parsers/http/actions/add-acl.go new file mode 100644 index 00000000..5c1826a4 --- /dev/null +++ b/config-parser/parsers/http/actions/add-acl.go @@ -0,0 +1,71 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +//nolint:dupl +package actions + +import ( + "fmt" + "strings" + + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +type AddACL struct { + FileName string + KeyFmt string + Cond string + CondTest string + Comment string +} + +func (f *AddACL) Parse(parts []string, parserType types.ParserType, comment string) error { + // we have filter trace [name ] [random-parsing] [random-forwarding] [hexdump] + if comment != "" { + f.Comment = comment + } + f.FileName = strings.TrimPrefix(parts[1], "add-acl(") + f.FileName = strings.TrimRight(f.FileName, ")") + if len(parts) >= 3 { + command, condition := common.SplitRequest(parts[2:]) // 2 not 3 ! + if len(command) > 0 { + f.KeyFmt = command[0] + } + if len(condition) > 1 { + f.Cond = condition[0] + f.CondTest = strings.Join(condition[1:], " ") + } + return nil + } + return fmt.Errorf("not enough params") +} + +func (f *AddACL) String() string { + keyfmt := "" + condition := "" + if f.KeyFmt != "" { + keyfmt = " " + f.KeyFmt + } + if f.Cond != "" { + condition = fmt.Sprintf(" %s %s", f.Cond, f.CondTest) + } + return fmt.Sprintf("add-acl(%s)%s%s", f.FileName, keyfmt, condition) +} + +func (f *AddACL) GetComment() string { + return f.Comment +} diff --git a/config-parser/parsers/http/actions/add-header.go b/config-parser/parsers/http/actions/add-header.go new file mode 100644 index 00000000..f8f0c10d --- /dev/null +++ b/config-parser/parsers/http/actions/add-header.go @@ -0,0 +1,62 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package actions + +import ( + "fmt" + "strings" + + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +type AddHeader struct { + Name string + Fmt string + Cond string + CondTest string + Comment string +} + +func (f *AddHeader) Parse(parts []string, parserType types.ParserType, comment string) error { + if comment != "" { + f.Comment = comment + } + if len(parts) >= 4 { + command, condition := common.SplitRequest(parts[3:]) + f.Name = parts[2] + f.Fmt = strings.Join(command, " ") + if len(condition) > 1 { + f.Cond = condition[0] + f.CondTest = strings.Join(condition[1:], " ") + } + return nil + } + return fmt.Errorf("not enough params") +} + +func (f *AddHeader) String() string { + condition := "" + if f.Cond != "" { + condition = fmt.Sprintf(" %s %s", f.Cond, f.CondTest) + } + return fmt.Sprintf("add-header %s %s%s", f.Name, f.Fmt, condition) +} + +func (f *AddHeader) GetComment() string { + return f.Comment +} diff --git a/config-parser/parsers/http/actions/allow.go b/config-parser/parsers/http/actions/allow.go new file mode 100644 index 00000000..a8735f89 --- /dev/null +++ b/config-parser/parsers/http/actions/allow.go @@ -0,0 +1,61 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package actions + +import ( + "fmt" + "strings" + + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +type Allow struct { + Cond string + CondTest string + Comment string +} + +func (f *Allow) Parse(parts []string, parserType types.ParserType, comment string) error { + // we have filter trace [name ] [random-parsing] [random-forwarding] [hexdump] + if comment != "" { + f.Comment = comment + } + if len(parts) >= 4 { + _, condition := common.SplitRequest(parts[2:]) // 2 not 3 ! + if len(condition) > 1 { + f.Cond = condition[0] + f.CondTest = strings.Join(condition[1:], " ") + } + return nil + } else if len(parts) == 2 { + return nil + } + return fmt.Errorf("not enough params") +} + +func (f *Allow) String() string { + condition := "" + if f.Cond != "" { + condition = fmt.Sprintf(" %s %s", f.Cond, f.CondTest) + } + return fmt.Sprintf("allow%s", condition) +} + +func (f *Allow) GetComment() string { + return f.Comment +} diff --git a/config-parser/parsers/http/actions/auth.go b/config-parser/parsers/http/actions/auth.go new file mode 100644 index 00000000..37512b61 --- /dev/null +++ b/config-parser/parsers/http/actions/auth.go @@ -0,0 +1,72 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package actions + +import ( + "fmt" + "strings" + + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +type Auth struct { + Realm string + Cond string + CondTest string + Comment string +} + +func (f *Auth) Parse(parts []string, parserType types.ParserType, comment string) error { + if comment != "" { + f.Comment = comment + } + if len(parts) >= 4 { + command, condition := common.SplitRequest(parts[2:]) + if len(command) > 1 && command[0] == "realm" { + f.Realm = command[1] + } + if len(condition) > 1 { + f.Cond = condition[0] + f.CondTest = strings.Join(condition[1:], " ") + } + return nil + } else if len(parts) == 2 { + return nil + } + return fmt.Errorf("not enough params") +} + +func (f *Auth) String() string { + var result strings.Builder + result.WriteString("auth") + if f.Realm != "" { + result.WriteString(" realm ") + result.WriteString(f.Realm) + } + if f.Cond != "" { + result.WriteString(" ") + result.WriteString(f.Cond) + result.WriteString(" ") + result.WriteString(f.CondTest) + } + return result.String() +} + +func (f *Auth) GetComment() string { + return f.Comment +} diff --git a/config-parser/parsers/http/actions/cache-store.go b/config-parser/parsers/http/actions/cache-store.go new file mode 100644 index 00000000..7d84cc4a --- /dev/null +++ b/config-parser/parsers/http/actions/cache-store.go @@ -0,0 +1,70 @@ +/* +Copyright 2022 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +//nolint:dupl +package actions + +import ( + "fmt" + "strings" + + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +type CacheStore struct { + Name string + Cond string + CondTest string + Comment string +} + +func (f *CacheStore) Parse(parts []string, parserType types.ParserType, comment string) error { + if comment != "" { + f.Comment = comment + } + if len(parts) >= 3 { + command, condition := common.SplitRequest(parts[2:]) + if len(command) < 1 { + return errors.ErrInvalidData + } + f.Name = command[0] + if len(condition) > 1 { + f.Cond = condition[0] + f.CondTest = strings.Join(condition[1:], " ") + } + return nil + } + return fmt.Errorf("not enough params") +} + +func (f *CacheStore) String() string { + var result strings.Builder + result.WriteString("cache-store ") + result.WriteString(f.Name) + if f.Cond != "" { + result.WriteString(" ") + result.WriteString(f.Cond) + result.WriteString(" ") + result.WriteString(f.CondTest) + } + return result.String() +} + +func (f *CacheStore) GetComment() string { + return f.Comment +} diff --git a/config-parser/parsers/http/actions/cache-use.go b/config-parser/parsers/http/actions/cache-use.go new file mode 100644 index 00000000..113e658b --- /dev/null +++ b/config-parser/parsers/http/actions/cache-use.go @@ -0,0 +1,70 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +//nolint:dupl +package actions + +import ( + "fmt" + "strings" + + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +type CacheUse struct { + Name string + Cond string + CondTest string + Comment string +} + +func (f *CacheUse) Parse(parts []string, parserType types.ParserType, comment string) error { + if comment != "" { + f.Comment = comment + } + if len(parts) >= 3 { + command, condition := common.SplitRequest(parts[2:]) + if len(command) < 1 { + return errors.ErrInvalidData + } + f.Name = command[0] + if len(condition) > 1 { + f.Cond = condition[0] + f.CondTest = strings.Join(condition[1:], " ") + } + return nil + } + return fmt.Errorf("not enough params") +} + +func (f *CacheUse) String() string { + var result strings.Builder + result.WriteString("cache-use ") + result.WriteString(f.Name) + if f.Cond != "" { + result.WriteString(" ") + result.WriteString(f.Cond) + result.WriteString(" ") + result.WriteString(f.CondTest) + } + return result.String() +} + +func (f *CacheUse) GetComment() string { + return f.Comment +} diff --git a/config-parser/parsers/http/actions/capture.go b/config-parser/parsers/http/actions/capture.go new file mode 100644 index 00000000..6c294460 --- /dev/null +++ b/config-parser/parsers/http/actions/capture.go @@ -0,0 +1,98 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package actions + +import ( + "fmt" + "strconv" + "strings" + + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +type Capture struct { // http-request capture sample [ len | id ] [ { if | unless } ] + Sample string + Len *int64 // Has to be > 0. + SlotID *int64 + Cond string + CondTest string + Comment string +} + +func (f *Capture) Parse(parts []string, parserType types.ParserType, comment string) error { + if comment != "" { + f.Comment = comment + } + if len(parts) >= 5 { + command, condition := common.SplitRequest(parts[2:]) + if len(command) < 3 { + return errors.ErrInvalidData + } + i, err := strconv.ParseInt(command[2], 10, 64) + if err != nil { + return errors.ErrInvalidData + } + f.Sample = command[0] + switch command[1] { + case "len": + // Response only takes id. + if parts[0] == "http-response" { + return errors.ErrInvalidData + } + f.Len = &i + case "id": + f.SlotID = &i + default: + return errors.ErrInvalidData + } + if len(condition) > 1 { + f.Cond = condition[0] + f.CondTest = strings.Join(condition[1:], " ") + } + return nil + } + return fmt.Errorf("not enough params") +} + +func (f *Capture) String() string { + var result strings.Builder + result.WriteString("capture ") + result.WriteString(f.Sample) + result.WriteString(" ") + if f.SlotID != nil { + result.WriteString("id") + result.WriteString(" ") + result.WriteString(strconv.FormatInt(*f.SlotID, 10)) + } else if f.Len != nil { + result.WriteString("len") + result.WriteString(" ") + result.WriteString(strconv.FormatInt(*f.Len, 10)) + } + if f.Cond != "" { + result.WriteString(" ") + result.WriteString(f.Cond) + result.WriteString(" ") + result.WriteString(f.CondTest) + } + return result.String() +} + +func (f *Capture) GetComment() string { + return f.Comment +} diff --git a/config-parser/parsers/http/actions/check-comment.go b/config-parser/parsers/http/actions/check-comment.go new file mode 100644 index 00000000..d85f2fe8 --- /dev/null +++ b/config-parser/parsers/http/actions/check-comment.go @@ -0,0 +1,51 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package actions + +import ( + "fmt" + + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +// http-check comment +type CheckComment struct { + LogMessage string + Comment string +} + +func (c *CheckComment) Parse(parts []string, parserType types.ParserType, comment string) error { + if comment != "" { + c.Comment = comment + } + + if len(parts) < 3 { + return fmt.Errorf("not enough params") + } + + c.LogMessage = parts[2] + + return nil +} + +func (c *CheckComment) String() string { + return "comment " + c.LogMessage +} + +func (c *CheckComment) GetComment() string { + return c.Comment +} diff --git a/config-parser/parsers/http/actions/check-disable-on-404.go b/config-parser/parsers/http/actions/check-disable-on-404.go new file mode 100644 index 00000000..e8337a4f --- /dev/null +++ b/config-parser/parsers/http/actions/check-disable-on-404.go @@ -0,0 +1,48 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package actions + +import ( + "fmt" + + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +// http-check disable-on-404 +type CheckDisableOn404 struct { + Comment string +} + +func (c *CheckDisableOn404) Parse(parts []string, parserType types.ParserType, comment string) error { + if comment != "" { + c.Comment = comment + } + + if len(parts) > 2 { + return fmt.Errorf("too many params") + } + + return nil +} + +func (c *CheckDisableOn404) String() string { + return "disable-on-404" +} + +func (c *CheckDisableOn404) GetComment() string { + return c.Comment +} diff --git a/config-parser/parsers/http/actions/check-send-state.go b/config-parser/parsers/http/actions/check-send-state.go new file mode 100644 index 00000000..fef88b55 --- /dev/null +++ b/config-parser/parsers/http/actions/check-send-state.go @@ -0,0 +1,48 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package actions + +import ( + "fmt" + + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +// http-check send-state +type CheckSendState struct { + Comment string +} + +func (c *CheckSendState) Parse(parts []string, parserType types.ParserType, comment string) error { + if comment != "" { + c.Comment = comment + } + + if len(parts) > 2 { + return fmt.Errorf("too many params") + } + + return nil +} + +func (c *CheckSendState) String() string { + return "send-state" +} + +func (c *CheckSendState) GetComment() string { + return c.Comment +} diff --git a/config-parser/parsers/http/actions/check-send.go b/config-parser/parsers/http/actions/check-send.go new file mode 100644 index 00000000..1e96efc3 --- /dev/null +++ b/config-parser/parsers/http/actions/check-send.go @@ -0,0 +1,113 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package actions + +import ( + "fmt" + "strings" + + "github.com/haproxytech/client-native/v5/config-parser/parsers/actions" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +// http-check send [meth ] [{ uri | uri-lf }>] [ver ] +// +// [hdr ]* [{ body | body-lf }] +// [comment ] +type CheckSend struct { + Method string + URI string + URILogFormat string + Version string + Header []CheckSendHeader + Body string + BodyLogFormat string + CheckComment string + Comment string +} + +type CheckSendHeader struct { + Name string + Format string +} + +func (c *CheckSend) Parse(parts []string, parserType types.ParserType, comment string) error { + if comment != "" { + c.Comment = comment + } + + if len(parts) < 3 { + return fmt.Errorf("not enough params") + } + + for i := 2; i < len(parts); i++ { + el := parts[i] + switch el { + case "meth": + actions.CheckParsePair(parts, &i, &c.Method) + case "uri": + actions.CheckParsePair(parts, &i, &c.URI) + case "uri-lf": + actions.CheckParsePair(parts, &i, &c.URILogFormat) + case "ver": + actions.CheckParsePair(parts, &i, &c.Version) + // NOTE: HAProxy config supports header values containing spaces, + // which config-parser normally would support with `\ `. + // However, because parts is split by spaces and hdr can be provided + // multiple times with other directives surrounding it, it's + // impossible to read ahead to put the pieces together. + // As such, header values with spaces are not supported. + case "hdr": + if (i+1) < len(parts) && (i+2) < len(parts) { + c.Header = append(c.Header, CheckSendHeader{Name: parts[i+1], Format: parts[i+2]}) + i++ + } + case "body": + actions.CheckParsePair(parts, &i, &c.Body) + case "body-lf": + actions.CheckParsePair(parts, &i, &c.BodyLogFormat) + case "comment": + actions.CheckParsePair(parts, &i, &c.CheckComment) + } + } + + return nil +} + +func (c *CheckSend) String() string { + sb := &strings.Builder{} + + sb.WriteString("send") + + actions.CheckWritePair(sb, "meth", c.Method) + actions.CheckWritePair(sb, "uri", c.URI) + actions.CheckWritePair(sb, "uri-lf", c.URILogFormat) + actions.CheckWritePair(sb, "ver", c.Version) + for _, h := range c.Header { + actions.CheckWritePair(sb, "hdr", h.Name) + actions.CheckWritePair(sb, "", h.Format) + } + actions.CheckWritePair(sb, "body", c.Body) + actions.CheckWritePair(sb, "body-lf", c.BodyLogFormat) + actions.CheckWritePair(sb, "comment", c.CheckComment) + + return sb.String() +} + +func (c *CheckSend) GetComment() string { + return c.Comment +} diff --git a/config-parser/parsers/http/actions/del-acl.go b/config-parser/parsers/http/actions/del-acl.go new file mode 100644 index 00000000..2c24e45f --- /dev/null +++ b/config-parser/parsers/http/actions/del-acl.go @@ -0,0 +1,71 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +//nolint:dupl +package actions + +import ( + "fmt" + "strings" + + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +type DelACL struct { + FileName string + KeyFmt string + Cond string + CondTest string + Comment string +} + +func (f *DelACL) Parse(parts []string, parserType types.ParserType, comment string) error { + // we have filter trace [name ] [random-parsing] [random-forwarding] [hexdump] + if comment != "" { + f.Comment = comment + } + f.FileName = strings.TrimPrefix(parts[1], "del-acl(") + f.FileName = strings.TrimRight(f.FileName, ")") + if len(parts) >= 3 { + command, condition := common.SplitRequest(parts[2:]) // 2 not 3 ! + if len(command) > 0 { + f.KeyFmt = command[0] + } + if len(condition) > 1 { + f.Cond = condition[0] + f.CondTest = strings.Join(condition[1:], " ") + } + return nil + } + return fmt.Errorf("not enough params") +} + +func (f *DelACL) String() string { + keyfmt := "" + condition := "" + if f.KeyFmt != "" { + keyfmt = " " + f.KeyFmt + } + if f.Cond != "" { + condition = fmt.Sprintf(" %s %s", f.Cond, f.CondTest) + } + return fmt.Sprintf("del-acl(%s)%s%s", f.FileName, keyfmt, condition) +} + +func (f *DelACL) GetComment() string { + return f.Comment +} diff --git a/config-parser/parsers/http/actions/del-header.go b/config-parser/parsers/http/actions/del-header.go new file mode 100644 index 00000000..2bd0df50 --- /dev/null +++ b/config-parser/parsers/http/actions/del-header.go @@ -0,0 +1,74 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package actions + +import ( + "fmt" + "strings" + + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +type DelHeader struct { + Name string + Method string + Cond string + CondTest string + Comment string +} + +// Parse parses { http-request | http-response } del-header [ { if | unless } ] +func (f *DelHeader) Parse(parts []string, parserType types.ParserType, comment string) error { + if comment != "" { + f.Comment = comment + } + + if len(parts) >= 3 { + command, condition := common.SplitRequest(parts[3:]) + f.Name = parts[2] + if len(command) > 1 && command[0] == "-m" { + f.Method = command[1] + } else if len(command) > 0 { + return fmt.Errorf("unknown params after name") + } + if len(condition) > 1 { + f.Cond = condition[0] + f.CondTest = strings.Join(condition[1:], " ") + } + return nil + } + return fmt.Errorf("not enough params") +} + +func (f *DelHeader) String() string { + sb := &strings.Builder{} + + sb.WriteString("del-header ") + sb.WriteString(f.Name) + if f.Method != "" { + sb.WriteString(fmt.Sprintf(" -m %s", f.Method)) + } + if f.Cond != "" { + sb.WriteString(fmt.Sprintf(" %s %s", f.Cond, f.CondTest)) + } + return sb.String() +} + +func (f *DelHeader) GetComment() string { + return f.Comment +} diff --git a/config-parser/parsers/http/actions/del-map.go b/config-parser/parsers/http/actions/del-map.go new file mode 100644 index 00000000..d5c11890 --- /dev/null +++ b/config-parser/parsers/http/actions/del-map.go @@ -0,0 +1,70 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package actions + +import ( + "fmt" + "strings" + + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +type DelMap struct { + FileName string + KeyFmt string + Cond string + CondTest string + Comment string +} + +func (f *DelMap) Parse(parts []string, parserType types.ParserType, comment string) error { + if comment != "" { + f.Comment = comment + } + f.FileName = strings.TrimPrefix(parts[1], "del-map(") + f.FileName = strings.TrimRight(f.FileName, ")") + if len(parts) >= 3 { + command, condition := common.SplitRequest(parts[2:]) + if len(command) == 0 { + return fmt.Errorf("not enough params") + } + f.KeyFmt = command[0] + if len(condition) > 1 { + f.Cond = condition[0] + f.CondTest = strings.Join(condition[1:], " ") + } + return nil + } + return fmt.Errorf("not enough params") +} + +func (f *DelMap) String() string { + keyfmt := "" + condition := "" + if f.KeyFmt != "" { + keyfmt = " " + f.KeyFmt + } + if f.Cond != "" { + condition = fmt.Sprintf(" %s %s", f.Cond, f.CondTest) + } + return fmt.Sprintf("del-map(%s)%s%s", f.FileName, keyfmt, condition) +} + +func (f *DelMap) GetComment() string { + return f.Comment +} diff --git a/config-parser/parsers/http/actions/deny.go b/config-parser/parsers/http/actions/deny.go new file mode 100644 index 00000000..533efce1 --- /dev/null +++ b/config-parser/parsers/http/actions/deny.go @@ -0,0 +1,139 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +//nolint:dupl +package actions + +import ( + "fmt" + "strconv" + "strings" + + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +type Deny struct { // http-request deny [status ] [content-type ] [ {default-errorfile | } ] [ hdr ]* [{if | unless} ] + Comment string + Status *int64 + ContentType string + ContentFormat string + Content string + Hdrs []*Hdr + Cond string + CondTest string +} + +func (f *Deny) Parse(parts []string, parserType types.ParserType, comment string) error { + f.Hdrs = []*Hdr{} + if comment != "" { + f.Comment = comment + } + if len(parts) >= 4 { + command, condition := common.SplitRequest(parts[2:]) + if len(command) > 1 { + for i := 0; i < len(command); i++ { + switch command[i] { + case "status", "deny_status": + i++ + code, err := strconv.ParseInt(command[i], 10, 64) + if err != nil { + return fmt.Errorf("failed to parse status code") + } + f.Status = &code + case "content-type": + i++ + f.ContentType = command[i] + case "errorfile", "errorfiles", "file", "lf-file", "string", "lf-string": + f.ContentFormat = command[i] + i++ + f.Content = command[i] + case "default-errorfiles": + f.ContentFormat = command[i] + case "hdr": + hdr := Hdr{} + if len(command) < i+3 { + return fmt.Errorf("failed to parse return hdr") + } + i++ + hdr.Name = command[i] + i++ + hdr.Fmt = command[i] + f.Hdrs = append(f.Hdrs, &hdr) + default: + return fmt.Errorf("failed to parse hdr") + } + } + } + if len(condition) > 1 { + f.Cond = condition[0] + f.CondTest = strings.Join(condition[1:], " ") + } + return nil + } else if len(parts) == 2 { + return nil + } + return fmt.Errorf("not enough params") +} + +func (f *Deny) String() string { + var result strings.Builder + result.WriteString("deny") + if f.Status != nil { + if IsPayload(f.ContentFormat) { + if allowedStatusCode(*f.Status) { + result.WriteString(" deny_status ") + result.WriteString(strconv.FormatInt(*f.Status, 10)) + } + } else { + if AllowedErrorCode(*f.Status) { + result.WriteString(" deny_status ") + result.WriteString(strconv.FormatInt(*f.Status, 10)) + } + } + } + if f.ContentType != "" { + result.WriteString(" content-type ") + result.WriteString(f.ContentType) + } + if f.ContentFormat != "" { + result.WriteString(" ") + result.WriteString(f.ContentFormat) + if f.Content != "" && f.ContentFormat != "default-errorfiles" { + result.WriteString(" ") + result.WriteString(f.Content) + } + } + if IsPayload(f.ContentFormat) { + for _, hdr := range f.Hdrs { + result.WriteString(" hdr ") + result.WriteString(hdr.Name) + result.WriteString(" ") + result.WriteString(hdr.Fmt) + } + } + if f.Cond != "" { + result.WriteString(" ") + result.WriteString(f.Cond) + result.WriteString(" ") + result.WriteString(f.CondTest) + } + return result.String() +} + +func (f *Deny) GetComment() string { + return f.Comment +} diff --git a/config-parser/parsers/http/actions/disable-l7-retry.go b/config-parser/parsers/http/actions/disable-l7-retry.go new file mode 100644 index 00000000..3df8c0c8 --- /dev/null +++ b/config-parser/parsers/http/actions/disable-l7-retry.go @@ -0,0 +1,63 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package actions + +import ( + "fmt" + "strings" + + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +type DisableL7Retry struct { + Name string + Cond string + CondTest string + Comment string +} + +func (f *DisableL7Retry) Parse(parts []string, parserType types.ParserType, comment string) error { + if comment != "" { + f.Comment = comment + } + if len(parts) >= 2 { + _, condition := common.SplitRequest(parts[2:]) + if len(condition) > 1 { + f.Cond = condition[0] + f.CondTest = strings.Join(condition[1:], " ") + } + return nil + } + return fmt.Errorf("not enough params") +} + +func (f *DisableL7Retry) String() string { + var result strings.Builder + result.WriteString("disable-l7-retry") + if f.Cond != "" { + result.WriteString(" ") + result.WriteString(f.Cond) + result.WriteString(" ") + result.WriteString(f.CondTest) + } + return result.String() +} + +func (f *DisableL7Retry) GetComment() string { + return f.Comment +} diff --git a/config-parser/parsers/http/actions/early-hint.go b/config-parser/parsers/http/actions/early-hint.go new file mode 100644 index 00000000..3f05dbbf --- /dev/null +++ b/config-parser/parsers/http/actions/early-hint.go @@ -0,0 +1,73 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package actions + +import ( + "fmt" + "strings" + + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +type EarlyHint struct { + Name string + Fmt string + Cond string + CondTest string + Comment string +} + +func (f *EarlyHint) Parse(parts []string, parserType types.ParserType, comment string) error { + if comment != "" { + f.Comment = comment + } + if len(parts) >= 4 { + command, condition := common.SplitRequest(parts[3:]) + if len(command) < 1 { + return errors.ErrInvalidData + } + f.Name = parts[2] + f.Fmt = strings.Join(command, " ") + if len(condition) > 1 { + f.Cond = condition[0] + f.CondTest = strings.Join(condition[1:], " ") + } + return nil + } + return fmt.Errorf("not enough params") +} + +func (f *EarlyHint) String() string { + var result strings.Builder + result.WriteString("early-hint ") + result.WriteString(f.Name) + result.WriteString(" ") + result.WriteString(f.Fmt) + if f.Cond != "" { + result.WriteString(" ") + result.WriteString(f.Cond) + result.WriteString(" ") + result.WriteString(f.CondTest) + } + return result.String() +} + +func (f *EarlyHint) GetComment() string { + return f.Comment +} diff --git a/config-parser/parsers/http/actions/normalize.go b/config-parser/parsers/http/actions/normalize.go new file mode 100644 index 00000000..f222956e --- /dev/null +++ b/config-parser/parsers/http/actions/normalize.go @@ -0,0 +1,94 @@ +/* +Copyright 2022 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package actions + +import ( + "fmt" + "strings" + + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +type NormalizeURI struct { + Normalizer string + Full bool + Strict bool + Cond string + CondTest string + Comment string +} + +func (f *NormalizeURI) Parse(parts []string, parserType types.ParserType, comment string) error { + if comment != "" { + f.Comment = comment + } + if len(parts) >= 3 { + command, condition := common.SplitRequest(parts[2:]) + if len(command) > 0 { + switch command[0] { + case "path-strip-dotdot": + f.Normalizer = command[0] + if len(command) > 1 && command[1] == "full" { + f.Full = true + } + case "percent-decode-unreserved", "percent-to-uppercase": + f.Normalizer = command[0] + if len(command) > 1 && command[1] == "strict" { + f.Strict = true + } + case "fragment-encode", "fragment-strip", "path-merge-slashes", "path-strip-dot", "query-sort-by-name": + f.Normalizer = command[0] + if len(command) > 1 { + return fmt.Errorf("unsupported keyword for %s: %s", command[0], command[1:]) + } + default: + return fmt.Errorf("unrecognized normalizer %s", command[0]) + } + if len(condition) > 1 { + f.Cond = condition[0] + f.CondTest = strings.Join(condition[1:], " ") + } + return nil + } + } + + return fmt.Errorf("not enough params") +} + +func (f *NormalizeURI) String() string { + var result strings.Builder + result.WriteString("normalize-uri ") + result.WriteString(f.Normalizer) + if f.Strict { + result.WriteString(" strict") + } + if f.Full { + result.WriteString(" full") + } + if f.Cond != "" { + result.WriteString(" ") + result.WriteString(f.Cond) + result.WriteString(" ") + result.WriteString(f.CondTest) + } + return result.String() +} + +func (f *NormalizeURI) GetComment() string { + return f.Comment +} diff --git a/config-parser/parsers/http/actions/redirect.go b/config-parser/parsers/http/actions/redirect.go new file mode 100644 index 00000000..61dc4164 --- /dev/null +++ b/config-parser/parsers/http/actions/redirect.go @@ -0,0 +1,107 @@ +/* +Copyright 2019 HAProxy Technologies + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package actions + +import ( + "fmt" + "strings" + + "github.com/haproxytech/client-native/v5/config-parser/common" + "github.com/haproxytech/client-native/v5/config-parser/errors" + "github.com/haproxytech/client-native/v5/config-parser/types" +) + +type Redirect struct { // http-request redirect location [code ] [