]> Cypherpunks repositories - gostls13.git/commitdiff
net/http/httputil: remove hop-by-hop headers in ReverseProxy
authorBrad Fitzpatrick <bradfitz@golang.org>
Mon, 11 Mar 2013 17:32:32 +0000 (10:32 -0700)
committerBrad Fitzpatrick <bradfitz@golang.org>
Mon, 11 Mar 2013 17:32:32 +0000 (10:32 -0700)
Fixes #2735

R=golang-dev, rsc
CC=golang-dev
https://golang.org/cl/7470048

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

index 134c452999d19955190b852aa77b2c5082508e09..5099d973ff3d7ad275f456bdb33da1ebde1b9c15 100644 (file)
@@ -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 {
index 8639271626fea3b6d239036e09ca0b73d70ec72b..3bcaa7f5c5892f6abf2be1d984210db2058ddf0d 100644 (file)
@@ -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 {