diff --git a/caddyhttp/proxy/proxy_test.go b/caddyhttp/proxy/proxy_test.go index f5d18b1d..e96898bd 100644 --- a/caddyhttp/proxy/proxy_test.go +++ b/caddyhttp/proxy/proxy_test.go @@ -450,6 +450,8 @@ func TestDownstreamHeadersUpdate(t *testing.T) { w.Header().Add("Merge-Me", "Initial") w.Header().Add("Remove-Me", "Remove-Value") w.Header().Add("Replace-Me", "Replace-Value") + w.Header().Add("Content-Type", "text/html") + w.Header().Add("Overwrite-Me", "Overwrite-Value") w.Write([]byte("Hello, client")) })) defer backend.Close() @@ -473,6 +475,10 @@ func TestDownstreamHeadersUpdate(t *testing.T) { t.Fatalf("Failed to create request: %v", err) } w := httptest.NewRecorder() + // set a predefined skip header + w.Header().Set("Content-Type", "text/css") + // set a predefined overwritten header + w.Header().Set("Overwrite-Me", "Initial") p.ServeHTTP(w, r) @@ -507,6 +513,22 @@ func TestDownstreamHeadersUpdate(t *testing.T) { t.Errorf("Downstream response does not contain expected %s header: expect %v, but got %v", headerKey, expect, got) } + + headerKey = "Content-Type" + got = actualHeaders[headerKey] + expect = []string{"text/css"} + if !reflect.DeepEqual(got, expect) { + t.Errorf("Downstream response does not contain expected %s header: expect %v, but got %v", + headerKey, expect, got) + } + + headerKey = "Overwrite-Me" + got = actualHeaders[headerKey] + expect = []string{"Overwrite-Value"} + if !reflect.DeepEqual(got, expect) { + t.Errorf("Downstream response does not contain expected %s header: expect %v, but got %v", + headerKey, expect, got) + } } var ( diff --git a/caddyhttp/proxy/reverseproxy.go b/caddyhttp/proxy/reverseproxy.go index 5038afcb..b355f5c6 100644 --- a/caddyhttp/proxy/reverseproxy.go +++ b/caddyhttp/proxy/reverseproxy.go @@ -252,8 +252,28 @@ func (rp *ReverseProxy) copyResponse(dst io.Writer, src io.Reader) { io.CopyBuffer(dst, src, buf.([]byte)) } +// skip these headers if they already exist. +// see https://github.com/mholt/caddy/pull/1112#discussion_r80092582 +var skipHeaders = map[string]struct{}{ + "Content-Type": {}, + "Content-Disposition": {}, + "Accept-Ranges": {}, + "Set-Cookie": {}, + "Cache-Control": {}, + "Expires": {}, +} + func copyHeader(dst, src http.Header) { for k, vv := range src { + if _, ok := dst[k]; ok { + // skip some predefined headers + // see https://github.com/mholt/caddy/issues/1086 + if _, shouldSkip := skipHeaders[k]; shouldSkip { + continue + } + // otherwise, overwrite + dst.Del(k) + } for _, v := range vv { dst.Add(k, v) }