Repository: avenga/couper
Pull request #259 (2021-06-23 15:57:07)

Fixup set_response_status behaviour during errors
Do not modify error responses


Patch:
diff --git a/eval/http.go b/eval/http.go
index fb8724f0..2dc46a92 100644
--- a/eval/http.go
+++ b/eval/http.go
@@ -297,14 +297,14 @@ func ApplyResponseContext(ctx context.Context, body hcl.Body, beresp *http.Respo
 
 	content, _, _ := body.PartialContent(config.BackendInlineSchema)
 	if attr, ok := content.Attributes["set_response_status"]; ok {
-		err, _ := ApplyResponseStatus(ctx, attr, beresp)
+		_, err := ApplyResponseStatus(ctx, attr, beresp)
 		return err
 	}
 
 	return nil
 }
 
-func ApplyResponseStatus(ctx context.Context, attr *hcl.Attribute, beresp *http.Response) (error, int) {
+func ApplyResponseStatus(ctx context.Context, attr *hcl.Attribute, beresp *http.Response) (int, error) {
 	var httpCtx *hcl.EvalContext
 	if c, ok := ctx.Value(ContextType).(*Context); ok {
 		httpCtx = c.eval
@@ -312,12 +312,13 @@ func ApplyResponseStatus(ctx context.Context, attr *hcl.Attribute, beresp *http.
 
 	val, attrDiags := attr.Expr.Value(httpCtx)
 	if seetie.SetSeverityLevel(attrDiags).HasErrors() {
-		return errors.Evaluation.With(attrDiags), 0
+		return 0, errors.Evaluation.With(attrDiags)
 	}
 
 	status := seetie.ValueToInt(val)
 	if status < 100 || status > 599 {
-		return errors.Configuration.Label("set_response_status").Messagef("invalid http status code: %d", status), 0
+		return 0, errors.Configuration.Label("set_response_status").
+			Messagef("invalid http status code: %d", status)
 	}
 
 	if beresp != nil {
@@ -334,7 +335,7 @@ func ApplyResponseStatus(ctx context.Context, attr *hcl.Attribute, beresp *http.
 		beresp.StatusCode = int(status)
 	}
 
-	return nil, int(status)
+	return int(status), nil
 }
 
 func ApplyResponseHeaderOps(ctx context.Context, body hcl.Body, headers ...http.Header) error {
diff --git a/handler/endpoint.go b/handler/endpoint.go
index 4528b6ec..5a87fec6 100644
--- a/handler/endpoint.go
+++ b/handler/endpoint.go
@@ -60,9 +60,10 @@ func NewEndpoint(opts *EndpointOptions, log *logrus.Entry, modifier []hcl.Body)
 
 func (e *Endpoint) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
 	var (
-		clientres *http.Response
-		err       error
-		log       = e.log.WithField("uid", req.Context().Value(request.UID))
+		clientres    *http.Response
+		err          error
+		log          = e.log.WithField("uid", req.Context().Value(request.UID))
+		isErrHandler = strings.HasPrefix(e.opts.LogHandlerKind, "error_") // weak ref
 	)
 
 	// Bind some values for logging purposes
@@ -136,7 +137,7 @@ func (e *Endpoint) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
 			// fallback
 			err = errors.Configuration
 
-			if strings.HasPrefix(e.opts.LogHandlerKind, "error_") { // weak ref
+			if isErrHandler {
 				err = req.Context().Value(request.Error).(*errors.Error)
 			} else {
 				// TODO determine error priority, may solved with error_handler
@@ -166,8 +167,9 @@ func (e *Endpoint) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
 		}
 
 		content, _, _ := e.opts.Context.PartialContent(config.Endpoint{}.Schema(true))
-		if attr, ok := content.Attributes["set_response_status"]; ok {
-			if applyErr, statusCode := eval.ApplyResponseStatus(evalContext, attr, nil); statusCode > 0 {
+		errFromCtx := req.Context().Value(request.Error)
+		if attr, ok := content.Attributes["set_response_status"]; isErrHandler && errFromCtx == err && ok {
+			if statusCode, applyErr := eval.ApplyResponseStatus(evalContext, attr, nil); statusCode > 0 {
 				if serr, k := serveErr.(*errors.Error); k {
 					serveErr = serr.Status(statusCode)
 				} else {


Test patch:
diff --git a/server/modifier_test.go b/server/modifier_test.go
index d606001b..fd549b80 100644
--- a/server/modifier_test.go
+++ b/server/modifier_test.go
@@ -107,6 +107,16 @@ func TestIntegration_SetResponseStatus(t *testing.T) {
 			expMessage: "", // logs without err have no/an empty message field
 			expStatus:  http.StatusNoContent,
 		},
+		{
+			path:       "/happy-path-only",
+			expMessage: `backend error: unsupported protocol scheme "couper"`,
+			expStatus:  http.StatusBadGateway,
+		},
+		{
+			path:       "/inception",
+			expMessage: `backend error: unsupported protocol scheme "couper"`,
+			expStatus:  http.StatusBadGateway,
+		},
 	} {
 		t.Run(tc.path, func(subT *testing.T) {
 			helper := test.New(subT)
diff --git a/server/testdata/integration/modifier/02_couper.hcl b/server/testdata/integration/modifier/02_couper.hcl
index 91602c8d..d00a7437 100644
--- a/server/testdata/integration/modifier/02_couper.hcl
+++ b/server/testdata/integration/modifier/02_couper.hcl
@@ -35,6 +35,18 @@ server "set-response-status" {
     }
     set_response_status = 204
   }
+
+  endpoint "/happy-path-only" {
+    proxy {
+      url = "couper://some.host/"
+    }
+    set_response_status = 418
+  }
+
+  endpoint "/inception" {
+    access_control = ["layer2"]
+    response {}
+  }
 }
 
 definitions {
@@ -45,5 +57,15 @@ definitions {
       set_response_status = 418
     }
   }
+
+  basic_auth "layer2" {
+    password = "sauerkraut"
+    error_handler {
+      request {
+        url = "couper://some.host/"
+      }
+      set_response_status = 418
+    }
+  }
 }