github.com/avenga/couper@v1.12.2/config/configload/error_handler.go (about) 1 package configload 2 3 import ( 4 "fmt" 5 "strings" 6 7 "github.com/hashicorp/hcl/v2" 8 "github.com/hashicorp/hcl/v2/gohcl" 9 "github.com/hashicorp/hcl/v2/hclsyntax" 10 11 "github.com/avenga/couper/config" 12 hclbody "github.com/avenga/couper/config/body" 13 "github.com/avenga/couper/config/configload/collect" 14 "github.com/avenga/couper/errors" 15 ) 16 17 type kindContent struct { 18 body *hclsyntax.Body 19 kinds []string 20 } 21 22 func configureErrorHandler(setter []collect.ErrorHandlerSetter, helper *helper) error { 23 for _, ehs := range setter { 24 body, ok := ehs.(config.Body) 25 if !ok { 26 continue 27 } 28 29 kinds, ehc, err := newErrorHandlerContent(body.HCLBody()) 30 if err != nil { 31 return err 32 } 33 34 for _, hc := range ehc { 35 errHandlerConf, confErr := newErrorHandlerConfig(hc, helper) 36 if confErr != nil { 37 return confErr 38 } 39 40 ehs.Set(errHandlerConf) 41 } 42 43 if handler, has := ehs.(config.ErrorHandlerGetter); has { 44 for _, defaultHandler := range handler.DefaultErrorHandlers() { 45 _, exist := kinds[errors.Wildcard] 46 if !exist { 47 for _, kind := range defaultHandler.Kinds { 48 _, exist = kinds[kind] 49 if exist { 50 break 51 } 52 } 53 } 54 55 if !exist { 56 ehs.Set(defaultHandler) 57 } 58 } 59 } 60 } 61 return nil 62 } 63 64 // newErrorHandlerContent reads given error_handler block contents and maps them by unique 65 // error kind declaration. 66 func newErrorHandlerContent(content *hclsyntax.Body) (map[string]struct{}, []kindContent, error) { 67 if content == nil { 68 return nil, nil, fmt.Errorf("empty hcl content") 69 } 70 71 configuredKinds := make(map[string]struct{}) 72 var kindContents []kindContent 73 74 for _, block := range hclbody.BlocksOfType(content, errorHandler) { 75 kinds, err := newKindsFromLabels(block, true) 76 if err != nil { 77 return nil, nil, err 78 } 79 for _, k := range kinds { 80 if _, exist := configuredKinds[k]; exist { 81 subjRange := block.DefRange() 82 if len(block.LabelRanges) > 0 { 83 subjRange = block.LabelRanges[0] 84 } 85 86 return nil, nil, hcl.Diagnostics{&hcl.Diagnostic{ 87 Severity: hcl.DiagError, 88 Summary: fmt.Sprintf("duplicate error type registration: %q", k), 89 Subject: &subjRange, 90 }} 91 } 92 93 if k != errors.Wildcard && !errors.IsKnown(k) { 94 subjRange := block.DefRange() 95 if len(block.LabelRanges) > 0 { 96 subjRange = block.LabelRanges[0] 97 } 98 99 return nil, nil, hcl.Diagnostics{&hcl.Diagnostic{ 100 Severity: hcl.DiagError, 101 Summary: fmt.Sprintf("error type is unknown: %q", k), 102 Subject: &subjRange, 103 }} 104 } 105 106 configuredKinds[k] = struct{}{} 107 } 108 kindContents = append(kindContents, kindContent{ 109 body: block.Body, 110 kinds: kinds, 111 }) 112 } 113 114 return configuredKinds, kindContents, nil 115 } 116 117 const errorHandlerLabelSep = " " 118 119 // newKindsFromLabels reads two possible kind formats and returns them per slice entry. 120 func newKindsFromLabels(block *hclsyntax.Block, addWildcard bool) ([]string, error) { 121 var allKinds []string 122 for _, kinds := range block.Labels { 123 all := strings.Split(kinds, errorHandlerLabelSep) 124 for i, a := range all { 125 if a == "" { 126 err := hcl.Diagnostic{ 127 Severity: hcl.DiagError, 128 Summary: "empty error_handler label", 129 Subject: &block.LabelRanges[i], 130 } 131 return nil, errors.Configuration.Message(err.Error()) 132 } 133 } 134 allKinds = append(allKinds, all...) 135 } 136 if addWildcard && len(allKinds) == 0 { 137 allKinds = append(allKinds, errors.Wildcard) 138 } 139 return allKinds, nil 140 } 141 142 func newErrorHandlerConfig(content kindContent, helper *helper) (*config.ErrorHandler, error) { 143 errHandlerConf := &config.ErrorHandler{Kinds: content.kinds} 144 if d := gohcl.DecodeBody(content.body, helper.context, errHandlerConf); d.HasErrors() { 145 return nil, d 146 } 147 148 ep := &config.Endpoint{ 149 ErrorFile: errHandlerConf.ErrorFile, 150 Proxies: errHandlerConf.Proxies, 151 Response: errHandlerConf.Response, 152 Remain: content.body, 153 Requests: errHandlerConf.Requests, 154 } 155 156 if err := refineEndpoints(helper, config.Endpoints{ep}, false, nil); err != nil { 157 return nil, err 158 } 159 160 errHandlerConf.Requests = ep.Requests 161 errHandlerConf.Proxies = ep.Proxies 162 163 return errHandlerConf, nil 164 }