diff --git a/proxy/context.go b/proxy/context.go index 418d76ed64..b839039f36 100644 --- a/proxy/context.go +++ b/proxy/context.go @@ -1,7 +1,6 @@ package proxy import ( - "bytes" stdlibcontext "context" "errors" "io" @@ -62,15 +61,15 @@ type noopFlushedResponseWriter struct { ignoredHeader http.Header } -func defaultBody() io.ReadCloser { - return io.NopCloser(&bytes.Buffer{}) +func noBody() io.ReadCloser { + return http.NoBody } func defaultResponse(r *http.Request) *http.Response { return &http.Response{ StatusCode: http.StatusNotFound, Header: make(http.Header), - Body: defaultBody(), + Body: noBody(), Request: r, } } @@ -89,7 +88,7 @@ func cloneRequestMetadata(r *http.Request) *http.Request { ProtoMinor: r.ProtoMinor, Header: cloneHeader(r.Header), Trailer: cloneHeader(r.Trailer), - Body: defaultBody(), + Body: noBody(), ContentLength: r.ContentLength, TransferEncoding: r.TransferEncoding, Close: r.Close, @@ -109,7 +108,7 @@ func cloneResponseMetadata(r *http.Response) *http.Response { ProtoMinor: r.ProtoMinor, Header: cloneHeader(r.Header), Trailer: cloneHeader(r.Trailer), - Body: defaultBody(), + Body: noBody(), ContentLength: r.ContentLength, TransferEncoding: r.TransferEncoding, Close: r.Close, @@ -180,7 +179,7 @@ func (c *context) ensureDefaultResponse() { } if c.response.Body == nil { - c.response.Body = defaultBody() + c.response.Body = noBody() } } @@ -235,7 +234,7 @@ func (c *context) Serve(r *http.Response) { } if r.Body == nil { - r.Body = defaultBody() + r.Body = noBody() } c.servedWithResponse = true diff --git a/proxy/defaultresponse_test.go b/proxy/defaultresponse_test.go new file mode 100644 index 0000000000..1107b415c8 --- /dev/null +++ b/proxy/defaultresponse_test.go @@ -0,0 +1,26 @@ +package proxy_test + +import ( + "net/http" + "testing" + + "github.com/zalando/skipper/eskip" + "github.com/zalando/skipper/proxy/proxytest" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestDefaultResponse(t *testing.T) { + p := proxytest.Config{ + Routes: eskip.MustParse(`* -> `), + }.Create() + defer p.Close() + + rsp, body, err := p.Client().GetBody(p.URL) + require.NoError(t, err) + + assert.Equal(t, http.StatusNotFound, rsp.StatusCode) + assert.Len(t, body, 0) + assert.Equal(t, "0", rsp.Header.Get("Content-Length")) +} diff --git a/proxy/proxy.go b/proxy/proxy.go index 5922eb4790..485d1a2600 100644 --- a/proxy/proxy.go +++ b/proxy/proxy.go @@ -958,8 +958,7 @@ func (p *Proxy) rejectBackend(ctx *context, req *http.Request) (*http.Response, if !p.limiters.Get(limit.Settings).Allow(req.Context(), s) { return &http.Response{ StatusCode: limit.StatusCode, - Header: http.Header{"Content-Length": []string{"0"}}, - Body: io.NopCloser(&bytes.Buffer{}), + Body: noBody(), }, true } } @@ -1211,6 +1210,9 @@ func (p *Proxy) serveResponse(ctx *context) { start := time.Now() p.tracing.logStreamEvent(ctx.proxySpan, StreamHeadersEvent, StartEvent) copyHeader(ctx.responseWriter.Header(), ctx.response.Header) + if ctx.response.Body == noBody() { + ctx.responseWriter.Header()["Content-Length"] = []string{"0"} + } if err := ctx.Request().Context().Err(); err != nil { // deadline exceeded or canceled in stdlib, client closed request