github.com/avenga/couper@v1.12.2/config/runtime/error_handler.go (about) 1 package runtime 2 3 import ( 4 "net/http" 5 "reflect" 6 7 "github.com/hashicorp/hcl/v2" 8 "github.com/hashicorp/hcl/v2/hclsyntax" 9 "github.com/sirupsen/logrus" 10 11 "github.com/avenga/couper/config" 12 "github.com/avenga/couper/errors" 13 "github.com/avenga/couper/eval" 14 "github.com/avenga/couper/eval/buffer" 15 "github.com/avenga/couper/handler" 16 ) 17 18 func newErrorHandler(ctx *hcl.EvalContext, conf *config.Couper, opts *protectedOptions, log *logrus.Entry, 19 defs ACDefinitions, references ...string) (http.Handler, buffer.Option, error) { 20 kindsHandler := map[string]http.Handler{} 21 var ehBufferOption buffer.Option 22 for _, ref := range references { 23 definition, ok := defs[ref] 24 if !ok { 25 continue 26 } 27 28 handlersPerKind := make(map[string]*config.ErrorHandler) 29 for _, h := range definition.ErrorHandler { 30 for _, k := range h.Kinds { 31 handlersPerKind[k] = h 32 } 33 } 34 35 if superKindMap, mapExists := errors.SuperTypesMapsByContext[ref]; mapExists { 36 // expand super-kinds: 37 // * set super-kind error handler for mapped sub-kinds, if no error handler for this sub-kind is already set 38 // * remove super-kind error handler for super-kind 39 for superKind, subKinds := range superKindMap { 40 if skHandler, skExists := handlersPerKind[superKind]; skExists { 41 for _, subKind := range subKinds { 42 if _, exists := handlersPerKind[subKind]; !exists { 43 handlersPerKind[subKind] = skHandler 44 } 45 } 46 47 delete(handlersPerKind, superKind) 48 } 49 } 50 } 51 52 for k, h := range handlersPerKind { 53 contextBody := h.HCLBody() 54 55 epConf := &config.Endpoint{ 56 Remain: contextBody, 57 Proxies: h.Proxies, 58 ErrorFile: h.ErrorFile, 59 Requests: h.Requests, 60 Response: h.Response, 61 } 62 63 emptyBody := &hclsyntax.Body{} 64 if epConf.Response == nil { // Set dummy resp to skip related requirement checks, allowed for error_handler. 65 epConf.Response = &config.Response{Remain: emptyBody} 66 } 67 68 epOpts, err := NewEndpointOptions(ctx, epConf, nil, opts.srvOpts, log, conf, opts.memStore) 69 if err != nil { 70 return nil, buffer.None, err 71 } 72 if epOpts.ErrorTemplate == nil || h.ErrorFile == "" { 73 epOpts.ErrorTemplate = opts.epOpts.ErrorTemplate 74 } 75 76 epOpts.ErrorTemplate = epOpts.ErrorTemplate.WithContextFunc(func(rw http.ResponseWriter, r *http.Request) { 77 beresp := &http.Response{Header: rw.Header()} 78 _ = eval.ApplyResponseContext(eval.ContextFromRequest(r).HCLContextSync(), contextBody, beresp) 79 }) 80 81 if epOpts.Response != nil && reflect.DeepEqual(epOpts.Response.Context, emptyBody) { 82 epOpts.Response = nil 83 } 84 85 epOpts.LogHandlerKind = "error_" + k 86 epOpts.IsErrorHandler = true 87 kindsHandler[k] = handler.NewEndpoint(epOpts, log, nil) 88 ehBufferOption |= epOpts.BufferOpts 89 } 90 } 91 92 return handler.NewErrorHandler(kindsHandler, opts.epOpts.ErrorTemplate), ehBufferOption, nil 93 }