Commit 1611839b authored by Tristan Colgate's avatar Tristan Colgate Committed by Brad Fitzpatrick

net/http/httputil: ReverseProxy should pass on unannounced Trailers

Trailers that are not announced in the Trailer must be passed on to
the downstream client.

Rather than iterate over each and find missing trailer values,
this re-adds all trailers to the headers if there is a disparity
between the number of announced trailers and the final number.

This fixes #20437

Change-Id: I867e85f45feff68616a9a9bd6f65f12d73825eb7
Reviewed-on: https://go-review.googlesource.com/43712Reviewed-by: 's avatarBrad Fitzpatrick <bradfitz@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
parent bc495c57
...@@ -233,7 +233,8 @@ func (p *ReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) { ...@@ -233,7 +233,8 @@ func (p *ReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
// The "Trailer" header isn't included in the Transport's response, // The "Trailer" header isn't included in the Transport's response,
// at least for *http.Transport. Build it up from Trailer. // at least for *http.Transport. Build it up from Trailer.
if len(res.Trailer) > 0 { announcedTrailers := len(res.Trailer)
if announcedTrailers > 0 {
trailerKeys := make([]string, 0, len(res.Trailer)) trailerKeys := make([]string, 0, len(res.Trailer))
for k := range res.Trailer { for k := range res.Trailer {
trailerKeys = append(trailerKeys, k) trailerKeys = append(trailerKeys, k)
...@@ -252,7 +253,18 @@ func (p *ReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) { ...@@ -252,7 +253,18 @@ func (p *ReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
} }
p.copyResponse(rw, res.Body) p.copyResponse(rw, res.Body)
res.Body.Close() // close now, instead of defer, to populate res.Trailer res.Body.Close() // close now, instead of defer, to populate res.Trailer
copyHeader(rw.Header(), res.Trailer)
if len(res.Trailer) == announcedTrailers {
copyHeader(rw.Header(), res.Trailer)
return
}
for k, vv := range res.Trailer {
k = http.TrailerPrefix + k
for _, v := range vv {
rw.Header().Add(k, v)
}
}
} }
func (p *ReverseProxy) copyResponse(dst io.Writer, src io.Reader) { func (p *ReverseProxy) copyResponse(dst io.Writer, src io.Reader) {
......
...@@ -69,6 +69,7 @@ func TestReverseProxy(t *testing.T) { ...@@ -69,6 +69,7 @@ func TestReverseProxy(t *testing.T) {
w.WriteHeader(backendStatus) w.WriteHeader(backendStatus)
w.Write([]byte(backendResponse)) w.Write([]byte(backendResponse))
w.Header().Set("X-Trailer", "trailer_value") w.Header().Set("X-Trailer", "trailer_value")
w.Header().Set(http.TrailerPrefix+"X-Unannounced-Trailer", "unannounced_trailer_value")
})) }))
defer backend.Close() defer backend.Close()
backendURL, err := url.Parse(backend.URL) backendURL, err := url.Parse(backend.URL)
...@@ -122,6 +123,9 @@ func TestReverseProxy(t *testing.T) { ...@@ -122,6 +123,9 @@ func TestReverseProxy(t *testing.T) {
if g, e := res.Trailer.Get("X-Trailer"), "trailer_value"; g != e { if g, e := res.Trailer.Get("X-Trailer"), "trailer_value"; g != e {
t.Errorf("Trailer(X-Trailer) = %q ; want %q", g, e) t.Errorf("Trailer(X-Trailer) = %q ; want %q", g, e)
} }
if g, e := res.Trailer.Get("X-Unannounced-Trailer"), "unannounced_trailer_value"; g != e {
t.Errorf("Trailer(X-Unannounced-Trailer) = %q ; want %q", g, e)
}
// Test that a backend failing to be reached or one which doesn't return // Test that a backend failing to be reached or one which doesn't return
// a response results in a StatusBadGateway. // a response results in a StatusBadGateway.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment