diff options
author | Brad Fitzpatrick <bradfitz@golang.org> | 2013-03-11 10:32:32 -0700 |
---|---|---|
committer | Brad Fitzpatrick <bradfitz@golang.org> | 2013-03-11 10:32:32 -0700 |
commit | ddc2c998a777e8fbada490822d5ca5223bb31903 (patch) | |
tree | b802f8ba100c74c4c2afc93df07b33b4d958c217 | |
parent | 6aad593e6a2d170773097e195c3abe4d9cf5d236 (diff) | |
download | go-ddc2c998a777e8fbada490822d5ca5223bb31903.tar.gz |
net/http/httputil: remove hop-by-hop headers in ReverseProxy
Fixes issue 2735
R=golang-dev, rsc
CC=golang-dev
https://codereview.appspot.com/7470048
-rw-r--r-- | src/pkg/net/http/httputil/reverseproxy.go | 36 | ||||
-rw-r--r-- | src/pkg/net/http/httputil/reverseproxy_test.go | 4 |
2 files changed, 32 insertions, 8 deletions
diff --git a/src/pkg/net/http/httputil/reverseproxy.go b/src/pkg/net/http/httputil/reverseproxy.go index 134c45299..5099d973f 100644 --- a/src/pkg/net/http/httputil/reverseproxy.go +++ b/src/pkg/net/http/httputil/reverseproxy.go @@ -81,6 +81,19 @@ func copyHeader(dst, src http.Header) { } } +// Hop-by-hop headers. These are removed when sent to the backend. +// http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html +var hopHeaders = []string{ + "Connection", + "Keep-Alive", + "Proxy-Authenticate", + "Proxy-Authorization", + "Te", // canonicalized version of "TE" + "Trailers", + "Transfer-Encoding", + "Upgrade", +} + func (p *ReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) { transport := p.Transport if transport == nil { @@ -96,14 +109,21 @@ func (p *ReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) { outreq.ProtoMinor = 1 outreq.Close = false - // Remove the connection header to the backend. We want a - // persistent connection, regardless of what the client sent - // to us. This is modifying the same underlying map from req - // (shallow copied above) so we only copy it if necessary. - if outreq.Header.Get("Connection") != "" { - outreq.Header = make(http.Header) - copyHeader(outreq.Header, req.Header) - outreq.Header.Del("Connection") + // Remove hop-by-hop headers to the backend. Especially + // important is "Connection" because we want a persistent + // connection, regardless of what the client sent to us. This + // is modifying the same underlying map from req (shallow + // copied above) so we only copy it if necessary. + copiedHeaders := false + for _, h := range hopHeaders { + if outreq.Header.Get(h) != "" { + if !copiedHeaders { + outreq.Header = make(http.Header) + copyHeader(outreq.Header, req.Header) + copiedHeaders = true + } + outreq.Header.Del(h) + } } if clientIP, _, err := net.SplitHostPort(req.RemoteAddr); err == nil { diff --git a/src/pkg/net/http/httputil/reverseproxy_test.go b/src/pkg/net/http/httputil/reverseproxy_test.go index 863927162..3bcaa7f5c 100644 --- a/src/pkg/net/http/httputil/reverseproxy_test.go +++ b/src/pkg/net/http/httputil/reverseproxy_test.go @@ -29,6 +29,9 @@ func TestReverseProxy(t *testing.T) { if c := r.Header.Get("Connection"); c != "" { t.Errorf("handler got Connection header value %q", c) } + if c := r.Header.Get("Upgrade"); c != "" { + t.Errorf("handler got Keep-Alive header value %q", c) + } if g, e := r.Host, "some-name"; g != e { t.Errorf("backend got Host header %q, want %q", g, e) } @@ -49,6 +52,7 @@ func TestReverseProxy(t *testing.T) { getReq, _ := http.NewRequest("GET", frontend.URL, nil) getReq.Host = "some-name" getReq.Header.Set("Connection", "close") + getReq.Header.Set("Upgrade", "foo") getReq.Close = true res, err := http.DefaultClient.Do(getReq) if err != nil { |