// Director must not access the provided Request
// after returning.
//
- // By default, the X-Forwarded-For, X-Forwarded-Host, and
- // X-Forwarded-Proto headers of the ourgoing request are
- // set as by the ProxyRequest.SetXForwarded function.
+ // By default, the X-Forwarded-For header is set to the
+ // value of the client IP address. If an X-Forwarded-For
+ // header already exists, the client IP is appended to the
+ // existing values. As a special case, if the header
+ // exists in the Request.Header map but has a nil value
+ // (such as when set by the Director func), the X-Forwarded-For
+ // header is not modified.
//
- // If an X-Forwarded-For header already exists, the client IP is
- // appended to the existing values. To prevent IP spoofing, be
- // sure to delete any pre-existing X-Forwarded-For header
- // coming from the client or an untrusted proxy.
- //
- // If a header exists in the Request.Header map but has a nil value
- // (such as when set by the Director func), it is not modified.
+ // To prevent IP spoofing, be sure to delete any pre-existing
+ // X-Forwarded-For header coming from the client or
+ // an untrusted proxy.
//
// Hop-by-hop headers are removed from the request after
// Director returns, which can remove headers added by
outreq.Header.Set("X-Forwarded-For", clientIP)
}
}
- if prior, ok := outreq.Header["X-Forwarded-Host"]; !(ok && prior == nil) {
- outreq.Header.Set("X-Forwarded-Host", req.Host)
- }
- if prior, ok := outreq.Header["X-Forwarded-Proto"]; !(ok && prior == nil) {
- if req.TLS == nil {
- outreq.Header.Set("X-Forwarded-Proto", "http")
- } else {
- outreq.Header.Set("X-Forwarded-Proto", "https")
- }
- }
}
if _, ok := outreq.Header["User-Agent"]; !ok {
if r.Header.Get("X-Forwarded-For") == "" {
t.Errorf("didn't get X-Forwarded-For header")
}
- if r.Header.Get("X-Forwarded-Host") == "" {
- t.Errorf("didn't get X-Forwarded-Host header")
- }
- if r.Header.Get("X-Forwarded-Proto") == "" {
- t.Errorf("didn't get X-Forwarded-Proto header")
- }
if c := r.Header.Get("Connection"); c != "" {
t.Errorf("handler got Connection header value %q", c)
}
const prevForwardedFor = "client ip"
const backendResponse = "I am the backend"
const backendStatus = 404
- const host = "some-name"
backend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Header.Get("X-Forwarded-For") == "" {
t.Errorf("didn't get X-Forwarded-For header")
if !strings.Contains(r.Header.Get("X-Forwarded-For"), prevForwardedFor) {
t.Errorf("X-Forwarded-For didn't contain prior data")
}
- if got, want := r.Header.Get("X-Forwarded-Host"), host; got != want {
- t.Errorf("X-Forwarded-Host = %q, want %q", got, want)
- }
- if got, want := r.Header.Get("X-Forwarded-Proto"), "http"; got != want {
- t.Errorf("X-Forwarded-Proto = %q, want %q", got, want)
- }
w.WriteHeader(backendStatus)
w.Write([]byte(backendResponse))
}))
defer frontend.Close()
getReq, _ := http.NewRequest("GET", frontend.URL, nil)
- getReq.Host = host
getReq.Header.Set("Connection", "close")
getReq.Header.Set("X-Forwarded-For", prevForwardedFor)
getReq.Close = true
}
}
-func TestXForwardedProtoTLS(t *testing.T) {
- backend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- if got, want := r.Header.Get("X-Forwarded-Proto"), "https"; got != want {
- t.Errorf("X-Forwarded-Proto = %q, want %q", got, want)
- }
- }))
- defer backend.Close()
- backendURL, err := url.Parse(backend.URL)
- if err != nil {
- t.Fatal(err)
- }
- proxyHandler := NewSingleHostReverseProxy(backendURL)
- frontend := httptest.NewTLSServer(proxyHandler)
- defer frontend.Close()
-
- getReq, _ := http.NewRequest("GET", frontend.URL, nil)
- getReq.Host = "some-host"
- _, err = frontend.Client().Do(getReq)
- if err != nil {
- t.Fatalf("Get: %v", err)
- }
-}
-
// Issue 38079: don't append to X-Forwarded-For if it's present but nil
func TestXForwardedFor_Omit(t *testing.T) {
backend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- for _, h := range []string{"X-Forwarded-For", "X-Forwarded-Host", "X-Forwarded-Proto"} {
- if v := r.Header.Get(h); v != "" {
- t.Errorf("got %v header: %q", h, v)
- }
+ if v := r.Header.Get("X-Forwarded-For"); v != "" {
+ t.Errorf("got X-Forwarded-For header: %q", v)
}
w.Write([]byte("hi"))
}))
oldDirector := proxyHandler.Director
proxyHandler.Director = func(r *http.Request) {
r.Header["X-Forwarded-For"] = nil
- r.Header["X-Forwarded-Host"] = nil
- r.Header["X-Forwarded-Proto"] = nil
oldDirector(r)
}
for _, h := range []string{
"From-Director",
"X-Forwarded-For",
- "X-Forwarded-Host",
- "X-Forwarded-Proto",
} {
if req.Header.Get(h) != "" {
t.Errorf("%v header mutation modified caller's request", h)