summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrad Fitzpatrick <bradfitz@golang.org>2013-03-11 10:32:32 -0700
committerBrad Fitzpatrick <bradfitz@golang.org>2013-03-11 10:32:32 -0700
commitddc2c998a777e8fbada490822d5ca5223bb31903 (patch)
treeb802f8ba100c74c4c2afc93df07b33b4d958c217
parent6aad593e6a2d170773097e195c3abe4d9cf5d236 (diff)
downloadgo-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.go36
-rw-r--r--src/pkg/net/http/httputil/reverseproxy_test.go4
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 {