diff --git a/eval/context.go b/eval/context.go index 411e26f4a..6f2e04215 100644 --- a/eval/context.go +++ b/eval/context.go @@ -161,8 +161,12 @@ func (c *Context) WithClientRequest(req *http.Request) *Context { } } port, _ := strconv.ParseInt(p, 10, 64) - // TODO how to set request.BufferOptions appropriately before WithClientRequest() is called - body, jsonBody := parseReqBody(req, true) + + var parseJSON bool + if opts, ok := ctx.Value(request.BufferOptions).(BufferOption); ok { + parseJSON = opts.JSONRequest() + } + body, jsonBody := parseReqBody(req, parseJSON) origin := NewRawOrigin(req.URL) ctx.eval.Variables[ClientRequest] = cty.ObjectVal(ctxMap.Merge(ContextMap{ @@ -472,7 +476,7 @@ func mergeBackendVariables(etx *hcl.EvalContext, key string, cmap ContextMap) { const defaultMaxMemory = 32 << 20 // 32 MB // parseForm populates the request PostForm field. -// As Proxy we should not consume the request body. +// As Proxy, we should not consume the request body. // Rewind body via GetBody method. func parseForm(r *http.Request) *http.Request { if r.GetBody == nil || r.Form != nil { diff --git a/eval/context_test.go b/eval/context_test.go index 524061340..ccf71bee6 100644 --- a/eval/context_test.go +++ b/eval/context_test.go @@ -11,7 +11,9 @@ import ( "testing" "github.com/google/go-cmp/cmp" + "github.com/hashicorp/hcl/v2" "github.com/hashicorp/hcl/v2/hclsimple" + "github.com/hashicorp/hcl/v2/hclsyntax" "github.com/zclconf/go-cty/cty" "github.com/avenga/couper/config/configload" @@ -87,10 +89,18 @@ func TestNewHTTPContext(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(subT *testing.T) { + file, diags := hclsyntax.ParseConfig([]byte(tt.hcl), "test.hcl", hcl.InitialPos) + if diags.HasErrors() { + subT.Fatal(diags) + } + bufferOption := eval.MustBuffer(file.Body) + helper := test.New(subT) req := httptest.NewRequest(tt.reqMethod, "https://couper.io/"+tt.query, tt.body) - *req = *req.Clone(context.WithValue(req.Context(), request.Endpoint, "couper-proxy")) + ctx := context.WithValue(req.Context(), request.Endpoint, "couper-proxy") + ctx = context.WithValue(ctx, request.BufferOptions, bufferOption) + *req = *req.Clone(ctx) for k, v := range tt.reqHeader { req.Header[k] = v @@ -99,13 +109,13 @@ func TestNewHTTPContext(t *testing.T) { bereq := req.Clone(context.Background()) beresp := newBeresp(bereq) - helper.Must(eval.SetGetBody(req, eval.BufferRequest, 512)) + helper.Must(eval.SetGetBody(req, bufferOption, 512)) - ctx := baseCtx.WithClientRequest(req).WithBeresp(beresp, cty.NilVal, false).HCLContext() - ctx.Functions = nil // we are not interested in a functions test + hclCtx := baseCtx.WithClientRequest(req).WithBeresp(beresp, cty.NilVal, false).HCLContext() + hclCtx.Functions = nil // we are not interested in a functions test var resultMap map[string]cty.Value - _ = hclsimple.Decode(tt.name+".hcl", []byte(tt.hcl), ctx, &resultMap) + _ = hclsimple.Decode(tt.name+".hcl", []byte(tt.hcl), hclCtx, &resultMap) for k, v := range tt.want { cv, ok := resultMap[k] diff --git a/handler/endpoint_test.go b/handler/endpoint_test.go index 7e5b9fa55..346eff253 100644 --- a/handler/endpoint_test.go +++ b/handler/endpoint_test.go @@ -206,9 +206,9 @@ func TestEndpoint_RoundTripContext_Variables_json_body(t *testing.T) { for _, method := range tt.methods { t.Run(method+" "+tt.name, func(subT *testing.T) { helper := test.New(subT) - + iBody := helper.NewInlineContext(tt.inlineCtx) backend := transport.NewBackend( - helper.NewInlineContext(tt.inlineCtx), + iBody, &transport.Config{NoProxyFromEnv: true}, nil, logger) ep := handler.NewEndpoint(&handler.EndpointOptions{ @@ -226,9 +226,12 @@ func TestEndpoint_RoundTripContext_Variables_json_body(t *testing.T) { req := httptest.NewRequest(method, "/", body) tt.header.Set(req) + bufferOption := eval.MustBuffer(iBody) + // normally injected by server/http - helper.Must(eval.SetGetBody(req, eval.BufferRequest, 1024)) - *req = *req.WithContext(eval.NewDefaultContext().WithClientRequest(req)) + helper.Must(eval.SetGetBody(req, bufferOption, 1024)) + ctx := context.WithValue(req.Context(), request.BufferOptions, bufferOption) + *req = *req.WithContext(eval.NewDefaultContext().WithClientRequest(req.WithContext(ctx))) rec := httptest.NewRecorder() rw := writer.NewResponseWriter(rec, "") // crucial for working ep due to res.Write() @@ -347,6 +350,7 @@ func TestEndpoint_RoundTripContext_Null_Eval(t *testing.T) { } else { req.Header.Set("Content-Type", "application/json") } + req = req.WithContext(context.WithValue(context.Background(), request.BufferOptions, bufOpts)) req = req.WithContext(eval.NewDefaultContext().WithClientRequest(req)) rec := httptest.NewRecorder() diff --git a/server/http.go b/server/http.go index 042c3aa40..8208bb7f9 100644 --- a/server/http.go +++ b/server/http.go @@ -252,7 +252,8 @@ func (s *HTTPServer) ServeHTTP(rw http.ResponseWriter, req *http.Request) { ctx = context.WithValue(ctx, request.Handler, hs.String()) } - if err = s.setGetBody(h, req); err != nil { + bufferOption, err := s.setGetBody(h, req) + if err != nil { h = mux.opts.ServerOptions.ServerErrTpl.WithError(err) } @@ -283,20 +284,21 @@ func (s *HTTPServer) ServeHTTP(rw http.ResponseWriter, req *http.Request) { } } + ctx = context.WithValue(ctx, request.BufferOptions, bufferOption) // due to the middleware callee stack we have to update the 'req' value. *req = *req.WithContext(s.evalCtx.WithClientRequest(req.WithContext(ctx))) h.ServeHTTP(rw, req) } -func (s *HTTPServer) setGetBody(h http.Handler, req *http.Request) error { +func (s *HTTPServer) setGetBody(h http.Handler, req *http.Request) (opt eval.BufferOption, err error) { inner := getChildHandler(h) - var err error if limitHandler, ok := inner.(handler.BodyLimit); ok { - err = eval.SetGetBody(req, limitHandler.BufferOptions(), limitHandler.RequestLimit()) + opt = limitHandler.BufferOptions() + err = eval.SetGetBody(req, opt, limitHandler.RequestLimit()) } - return err + return opt, err } // getHost configures the host from the incoming request host based on diff --git a/server/testdata/integration/endpoint_eval/15_couper.hcl b/server/testdata/integration/endpoint_eval/15_couper.hcl index 6e58351bf..b1600997d 100644 --- a/server/testdata/integration/endpoint_eval/15_couper.hcl +++ b/server/testdata/integration/endpoint_eval/15_couper.hcl @@ -2,6 +2,9 @@ server "bodies" { endpoint "/req" { response { status = 200 + headers = { + x-json: request.json_body + } json_body = request } } diff --git a/server/testdata/integration/endpoint_eval/19_couper.hcl b/server/testdata/integration/endpoint_eval/19_couper.hcl index 8d349c937..c36086e1b 100644 --- a/server/testdata/integration/endpoint_eval/19_couper.hcl +++ b/server/testdata/integration/endpoint_eval/19_couper.hcl @@ -1,6 +1,9 @@ server "request" { endpoint "/**" { response { + headers = { + x-json = request.json_body + } json_body = request } }