[BUG] proxy chunked enconding upstream erase body when record is active
Describe the bug I setup a chunked encoding response http server at localhost:9394, and try use host.ProxyHandle to proxy it when ctx.Record() is call in middleware, that lead to body be erased.
To Reproduce Steps to reproduce the behavior:
package main
import (
"github.com/kataras/iris/v12"
"github.com/kataras/iris/v12/context"
"github.com/kataras/iris/v12/core/host"
"net/http"
"net/http/httputil"
"net/url"
)
func recorder(ctx *context.Context) {
if _, ok := ctx.IsRecording(); !ok {
ctx.Record()
}
ctx.Next()
}
func main() {
http.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) {
chunkedWriter := httputil.NewChunkedWriter(writer)
writer.Header().Set("Transfer-Encoding", "chunked")
chunkedWriter.Write([]byte("hello"))
chunkedWriter.Close()
})
go http.ListenAndServe(":9394", nil)
app := iris.New()
app.Use(recorder)
u, _ := url.Parse("http://localhost:9394")
app.Get("/", iris.FromStd(host.ProxyHandler(u, nil)))
app.Run(iris.Addr(":9395"))
}
Expected behavior body response to client as normal
iris.Version
- v12.1.8
- go 1.16.4
Please make sure the bug is reproducible over the master branch:
$ cd PROJECT
$ go get -u github.com/kataras/iris/v12@master
$ go run .
Additional context a quick workaround is supply ModifyResponse to httputil.ReverseProxy, modify response.ContentLength to 0 when it's -1. (http.ReverseProxy will not call ResponseWriter.Flush in this situation)
Hi
I think the bug come from this in go 1.16.4
var hopHeaders = []string{
...
"Transfer-Encoding",
...
}
func (p *ReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
...
for _, h := range hopHeaders {
res.Header.Del(h)
}
...
}
And in recorder Flush, but i don't understand why we should check w.headers.Get("Transfer-Encoding") == "chunked".
// Flush sends any buffered data to the client.
func (w *ResponseRecorder) Flush() {
// This fixes response recorder when chunked + Flush is used.
if w.headers.Get("Transfer-Encoding") == "chunked" {
if w.Written() == NoWritten {
if len(w.headers) > 0 {
h := w.ResponseWriter.Header()
// note: we don't reset the current underline's headers.
for k, v := range w.headers {
h[k] = v
}
}
}
if len(w.chunks) > 0 {
w.ResponseWriter.Write(w.chunks)
}
}
w.ResponseWriter.Flush()
w.ResetBody()
}