diff --git a/proxy/plugin.go b/proxy/plugin.go index 8a548b6a8..69b98b3f4 100644 --- a/proxy/plugin.go +++ b/proxy/plugin.go @@ -15,7 +15,7 @@ import ( // NewPluginMiddleware returns an endpoint middleware wrapped (if required) with the plugin middleware. // The plugin middleware will try to load all the required plugins from the register and execute them in order. -// RequestModifiers are executed before passing the request to the next middlware. ResponseModifiers are executed +// RequestModifiers are executed before passing the request to the next middleware. ResponseModifiers are executed // once the response is returned from the next middleware. func NewPluginMiddleware(logger logging.Logger, endpoint *config.EndpointConfig) Middleware { cfg, ok := endpoint.ExtraConfig[plugin.Namespace].(map[string]interface{}) @@ -29,7 +29,7 @@ func NewPluginMiddleware(logger logging.Logger, endpoint *config.EndpointConfig) // NewBackendPluginMiddleware returns a backend middleware wrapped (if required) with the plugin middleware. // The plugin middleware will try to load all the required plugins from the register and execute them in order. -// RequestModifiers are executed before passing the request to the next middlware. ResponseModifiers are executed +// RequestModifiers are executed before passing the request to the next middleware. ResponseModifiers are executed // once the response is returned from the next middleware. func NewBackendPluginMiddleware(logger logging.Logger, remote *config.Backend) Middleware { cfg, ok := remote.ExtraConfig[plugin.Namespace].(map[string]interface{}) @@ -88,12 +88,7 @@ func newPluginMiddleware(logger logging.Logger, tag, pattern string, cfg map[str if totReqModifiers == 0 { return func(ctx context.Context, r *Request) (*Response, error) { - resp, err := next[0](ctx, r) - if err != nil { - return resp, err - } - - return executeResponseModifiers(respModifiers, resp) + return nextProxyWithResponseModifiers(ctx, r, next[0], respModifiers) } } @@ -116,16 +111,22 @@ func newPluginMiddleware(logger logging.Logger, tag, pattern string, cfg map[str return nil, err } - resp, err := next[0](ctx, r) - if err != nil { - return resp, err - } - - return executeResponseModifiers(respModifiers, resp) + return nextProxyWithResponseModifiers(ctx, r, next[0], respModifiers) } } } +func nextProxyWithResponseModifiers(ctx context.Context, r *Request, next Proxy, respModifiers []func(interface{}) (interface{}, error)) (*Response, error) { + resp, err := next(ctx, r) + // merged responses of multiple backends will have a non nil resp if at least one of the backends responds + // successfully + if err != nil && resp == nil { + return resp, err + } + + return executeResponseModifiers(respModifiers, resp) +} + func executeRequestModifiers(reqModifiers []func(interface{}) (interface{}, error), r *Request) (*Request, error) { var tmp RequestWrapper tmp = &requestWrapper{ diff --git a/proxy/plugin/tests/logger/main.go b/proxy/plugin/tests/logger/main.go index e5ab5932a..d1969dfc6 100644 --- a/proxy/plugin/tests/logger/main.go +++ b/proxy/plugin/tests/logger/main.go @@ -25,7 +25,7 @@ func (r registerer) RegisterModifiers(f func( appliesToResponse bool, )) { f(string(r)+"-request", r.requestModifierFactory, true, false) - f(string(r)+"-response", r.reqsponseModifierFactory, false, true) + f(string(r)+"-response", r.responseModifierFactory, false, true) } func (registerer) RegisterLogger(in interface{}) { @@ -47,7 +47,7 @@ func (registerer) requestModifierFactory(_ map[string]interface{}) func(interfac return func(input interface{}) (interface{}, error) { req, ok := input.(RequestWrapper) if !ok { - return nil, unkownTypeErr + return nil, errUnknownType } return modifier(req), nil @@ -58,7 +58,7 @@ func (registerer) requestModifierFactory(_ map[string]interface{}) func(interfac return func(input interface{}) (interface{}, error) { req, ok := input.(RequestWrapper) if !ok { - return nil, unkownTypeErr + return nil, errUnknownType } r := modifier(req) @@ -74,7 +74,7 @@ func (registerer) requestModifierFactory(_ map[string]interface{}) func(interfac } } -func (registerer) reqsponseModifierFactory(_ map[string]interface{}) func(interface{}) (interface{}, error) { +func (registerer) responseModifierFactory(_ map[string]interface{}) func(interface{}) (interface{}, error) { // check the cfg. If the modifier requires some configuration, // it should be under the name of the plugin. // ex: if this modifier required some A and B config params @@ -96,7 +96,7 @@ func (registerer) reqsponseModifierFactory(_ map[string]interface{}) func(interf return func(input interface{}) (interface{}, error) { resp, ok := input.(ResponseWrapper) if !ok { - return nil, unkownTypeErr + return nil, errUnknownType } fmt.Println("data:", resp.Data()) @@ -112,7 +112,7 @@ func (registerer) reqsponseModifierFactory(_ map[string]interface{}) func(interf return func(input interface{}) (interface{}, error) { resp, ok := input.(ResponseWrapper) if !ok { - return nil, unkownTypeErr + return nil, errUnknownType } logger.Debug("data:", resp.Data()) @@ -136,7 +136,7 @@ func modifier(req RequestWrapper) requestWrapper { } } -var unkownTypeErr = errors.New("unknown request type") +var errUnknownType = errors.New("unknown request type") type ResponseWrapper interface { Data() map[string]interface{} diff --git a/proxy/plugin_test.go b/proxy/plugin_test.go index 7460ebfda..8e946059e 100644 --- a/proxy/plugin_test.go +++ b/proxy/plugin_test.go @@ -73,6 +73,59 @@ func TestNewPluginMiddleware_logger(t *testing.T) { } } +func TestNewPluginMiddleware_merge_error(t *testing.T) { + plugin.LoadWithLogger("./plugin/tests", ".so", plugin.RegisterModifier, logging.NoOp) + + validator := func(ctx context.Context, r *Request) (*Response, error) { + return &Response{ + Data: map[string]interface{}{"foo": "bar"}, + IsComplete: true, + Metadata: Metadata{ + Headers: map[string][]string{}, + StatusCode: 0, + }, + }, mergeError{errs: []error{fmt.Errorf("some backend error")}} + } + + bknd := NewBackendPluginMiddleware( + logging.NoOp, + &config.Backend{ + ExtraConfig: map[string]interface{}{ + plugin.Namespace: map[string]interface{}{ + "name": []interface{}{"lura-request-modifier-example-response"}, + }, + }, + }, + )(validator) + + p := NewPluginMiddleware( + logging.NoOp, + &config.EndpointConfig{ + ExtraConfig: map[string]interface{}{ + plugin.Namespace: map[string]interface{}{ + "name": []interface{}{ + "lura-request-modifier-example-response", + }, + }, + }, + }, + )(bknd) + + resp, err := p(context.Background(), &Request{Path: "/bar"}) + if err != nil { + t.Error(err.Error()) + } + + if resp == nil { + t.Errorf("unexpected response: %v", resp) + return + } + + if v, ok := resp.Data["foo"].(string); !ok || v != "bar" { + t.Errorf("unexpected foo value: %v", resp.Data["foo"]) + } +} + func TestNewPluginMiddleware_error_request(t *testing.T) { plugin.LoadWithLogger("./plugin/tests", ".so", plugin.RegisterModifier, logging.NoOp)