]> Cypherpunks repositories - gostls13.git/commitdiff
net/http/httputil: ReverseProxy should pass on unannounced Trailers
authorTristan Colgate <tcolgate@gmail.com>
Sat, 20 May 2017 13:50:06 +0000 (14:50 +0100)
committerBrad Fitzpatrick <bradfitz@golang.org>
Mon, 22 May 2017 18:34:09 +0000 (18:34 +0000)
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/43712
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>

src/net/http/httputil/reverseproxy.go
src/net/http/httputil/reverseproxy_test.go

index 488db9731330f3f4d8eac3e0f9554f8d36eeacab..fd78d45602d8cec3498f185aaa824c5b26b36ba8 100644 (file)
@@ -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,
        // 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))
                for k := range res.Trailer {
                        trailerKeys = append(trailerKeys, k)
@@ -252,7 +253,18 @@ func (p *ReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
        }
        p.copyResponse(rw, res.Body)
        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) {
index 008e4e717fbad0a2eac460514f4325a22970b04b..04ac6b4059141c9526ee0a983e775136fb184e58 100644 (file)
@@ -69,6 +69,7 @@ func TestReverseProxy(t *testing.T) {
                w.WriteHeader(backendStatus)
                w.Write([]byte(backendResponse))
                w.Header().Set("X-Trailer", "trailer_value")
+               w.Header().Set(http.TrailerPrefix+"X-Unannounced-Trailer", "unannounced_trailer_value")
        }))
        defer backend.Close()
        backendURL, err := url.Parse(backend.URL)
@@ -122,6 +123,9 @@ func TestReverseProxy(t *testing.T) {
        if g, e := res.Trailer.Get("X-Trailer"), "trailer_value"; 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
        // a response results in a StatusBadGateway.