rw.WriteHeader(http.StatusInternalServerError)
return
}
- defer res.Body.Close()
for _, h := range hopHeaders {
res.Header.Del(h)
copyHeader(rw.Header(), res.Header)
+ // 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 {
+ var trailerKeys []string
+ for k := range res.Trailer {
+ trailerKeys = append(trailerKeys, k)
+ }
+ rw.Header().Add("Trailer", strings.Join(trailerKeys, ", "))
+ }
+
rw.WriteHeader(res.StatusCode)
+ if len(res.Trailer) > 0 {
+ // Force chunking if we saw a response trailer.
+ // This prevents net/http from calculating the length for short
+ // bodies and adding a Content-Length.
+ if fl, ok := rw.(http.Flusher); ok {
+ fl.Flush()
+ }
+ }
p.copyResponse(rw, res.Body)
+ res.Body.Close() // close now, instead of defer, to populate res.Trailer
+ copyHeader(rw.Header(), res.Trailer)
}
func (p *ReverseProxy) copyResponse(dst io.Writer, src io.Reader) {
"net/http"
"net/http/httptest"
"net/url"
+ "reflect"
"runtime"
"strings"
"testing"
if g, e := r.Host, "some-name"; g != e {
t.Errorf("backend got Host header %q, want %q", g, e)
}
+ w.Header().Set("Trailer", "X-Trailer")
w.Header().Set("X-Foo", "bar")
w.Header().Set("Upgrade", "foo")
w.Header().Set(fakeHopHeader, "foo")
http.SetCookie(w, &http.Cookie{Name: "flavor", Value: "chocolateChip"})
w.WriteHeader(backendStatus)
w.Write([]byte(backendResponse))
+ w.Header().Set("X-Trailer", "trailer_value")
}))
defer backend.Close()
backendURL, err := url.Parse(backend.URL)
if g, e := len(res.Header["Set-Cookie"]), 1; g != e {
t.Fatalf("got %d SetCookies, want %d", g, e)
}
+ if g, e := res.Trailer, (http.Header{"X-Trailer": nil}); !reflect.DeepEqual(g, e) {
+ t.Errorf("before reading body, Trailer = %#v; want %#v", g, e)
+ }
if cookie := res.Cookies()[0]; cookie.Name != "flavor" {
t.Errorf("unexpected cookie %q", cookie.Name)
}
if g, e := string(bodyBytes), backendResponse; g != e {
t.Errorf("got body %q; expected %q", g, e)
}
+ if g, e := res.Trailer.Get("X-Trailer"), "trailer_value"; g != e {
+ t.Errorf("Trailer(X-Trailer) = %q ; want %q", g, e)
+ }
+
}
func TestXForwardedFor(t *testing.T) {