diff --git a/gateway/handlers/forwarding_proxy.go b/gateway/handlers/forwarding_proxy.go index 04a76e31..d9520f86 100644 --- a/gateway/handlers/forwarding_proxy.go +++ b/gateway/handlers/forwarding_proxy.go @@ -80,6 +80,7 @@ func buildUpstreamRequest(r *http.Request, baseURL string, requestURL string) *h upstreamReq, _ := http.NewRequest(r.Method, url, nil) copyHeaders(upstreamReq.Header, &r.Header) + deleteHeaders(&upstreamReq.Header, &hopHeaders) if len(r.Host) > 0 && upstreamReq.Header.Get("X-Forwarded-Host") == "" { upstreamReq.Header["X-Forwarded-Host"] = []string{r.Host} @@ -141,6 +142,12 @@ func copyHeaders(destination http.Header, source *http.Header) { } } +func deleteHeaders(target *http.Header, exclude *[]string) { + for _, h := range *exclude { + target.Del(h) + } +} + // SingleHostBaseURLResolver resolves URLs against a single BaseURL type SingleHostBaseURLResolver struct { BaseURL string @@ -208,3 +215,20 @@ func (f FunctionPrefixTrimmingURLPathTransformer) Transform(r *http.Request) str return ret } + +// Hop-by-hop headers. These are removed when sent to the backend. +// As of RFC 7230, hop-by-hop headers are required to appear in the +// Connection header field. These are the headers defined by the +// obsoleted RFC 2616 (section 13.5.1) and are used for backward +// compatibility. +var hopHeaders = []string{ + "Connection", + "Proxy-Connection", // non-standard but still sent by libcurl and rejected by e.g. google + "Keep-Alive", + "Proxy-Authenticate", + "Proxy-Authorization", + "Te", // canonicalized version of "TE" + "Trailer", // not Trailers per URL above; https://www.rfc-editor.org/errata_search.php?eid=4522 + "Transfer-Encoding", + "Upgrade", +} diff --git a/gateway/handlers/forwarding_proxy_test.go b/gateway/handlers/forwarding_proxy_test.go index c424d18c..ed0f15b1 100644 --- a/gateway/handlers/forwarding_proxy_test.go +++ b/gateway/handlers/forwarding_proxy_test.go @@ -338,3 +338,22 @@ func Test_buildUpstreamRequest_WithPathAndQuery(t *testing.T) { } } + +func Test_deleteHeaders(t *testing.T) { + h := http.Header{} + target := "X-Dont-Forward" + h.Add(target, "value1") + h.Add("X-Keep-This", "value2") + + deleteHeaders(&h, &[]string{target}) + + if h.Get(target) == "value1" { + t.Errorf("want %s to be removed from headers", target) + t.Fail() + } + + if h.Get("X-Keep-This") != "value2" { + t.Errorf("want %s to remain in headers", "X-Keep-This") + t.Fail() + } +}