|
@ -23,6 +23,7 @@ import ( |
|
|
"io" |
|
|
"io" |
|
|
"net" |
|
|
"net" |
|
|
"net/http" |
|
|
"net/http" |
|
|
|
|
|
"net/textproto" |
|
|
"net/url" |
|
|
"net/url" |
|
|
"regexp" |
|
|
"regexp" |
|
|
"strconv" |
|
|
"strconv" |
|
@ -80,10 +81,13 @@ type Handler struct { |
|
|
// Upstreams is the list of backends to proxy to.
|
|
|
// Upstreams is the list of backends to proxy to.
|
|
|
Upstreams UpstreamPool `json:"upstreams,omitempty"` |
|
|
Upstreams UpstreamPool `json:"upstreams,omitempty"` |
|
|
|
|
|
|
|
|
// Adjusts how often to flush the response buffer. A
|
|
|
// Adjusts how often to flush the response buffer. By default,
|
|
|
// negative value disables response buffering.
|
|
|
// no periodic flushing is done. A negative value disables
|
|
|
// TODO: figure out good defaults and write docs for this
|
|
|
// response buffering, and flushes immediately after each
|
|
|
// (see https://github.com/caddyserver/caddy/issues/1460)
|
|
|
// write to the client. This option is ignored when the upstream's
|
|
|
|
|
|
// response is recognized as a streaming response, or if its
|
|
|
|
|
|
// content length is -1; for such responses, writes are flushed
|
|
|
|
|
|
// to the client immediately.
|
|
|
FlushInterval caddy.Duration `json:"flush_interval,omitempty"` |
|
|
FlushInterval caddy.Duration `json:"flush_interval,omitempty"` |
|
|
|
|
|
|
|
|
// Headers manipulates headers between Caddy and the backend.
|
|
|
// Headers manipulates headers between Caddy and the backend.
|
|
@ -528,13 +532,19 @@ func (h Handler) prepareRequest(req *http.Request) error { |
|
|
// If we aren't the first proxy retain prior
|
|
|
// If we aren't the first proxy retain prior
|
|
|
// X-Forwarded-For information as a comma+space
|
|
|
// X-Forwarded-For information as a comma+space
|
|
|
// separated list and fold multiple headers into one.
|
|
|
// separated list and fold multiple headers into one.
|
|
|
if prior, ok := req.Header["X-Forwarded-For"]; ok { |
|
|
prior, ok := req.Header["X-Forwarded-For"] |
|
|
|
|
|
omit := ok && prior == nil // Issue 38079: nil now means don't populate the header
|
|
|
|
|
|
if len(prior) > 0 { |
|
|
clientIP = strings.Join(prior, ", ") + ", " + clientIP |
|
|
clientIP = strings.Join(prior, ", ") + ", " + clientIP |
|
|
} |
|
|
} |
|
|
req.Header.Set("X-Forwarded-For", clientIP) |
|
|
if !omit { |
|
|
|
|
|
req.Header.Set("X-Forwarded-For", clientIP) |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if req.Header.Get("X-Forwarded-Proto") == "" { |
|
|
prior, ok := req.Header["X-Forwarded-Proto"] |
|
|
|
|
|
omit := ok && prior == nil |
|
|
|
|
|
if len(prior) == 0 && !omit { |
|
|
// set X-Forwarded-Proto; many backend apps expect this too
|
|
|
// set X-Forwarded-Proto; many backend apps expect this too
|
|
|
proto := "https" |
|
|
proto := "https" |
|
|
if req.TLS == nil { |
|
|
if req.TLS == nil { |
|
@ -827,10 +837,10 @@ func upgradeType(h http.Header) string { |
|
|
// removeConnectionHeaders removes hop-by-hop headers listed in the "Connection" header of h.
|
|
|
// removeConnectionHeaders removes hop-by-hop headers listed in the "Connection" header of h.
|
|
|
// See RFC 7230, section 6.1
|
|
|
// See RFC 7230, section 6.1
|
|
|
func removeConnectionHeaders(h http.Header) { |
|
|
func removeConnectionHeaders(h http.Header) { |
|
|
if c := h.Get("Connection"); c != "" { |
|
|
for _, f := range h["Connection"] { |
|
|
for _, f := range strings.Split(c, ",") { |
|
|
for _, sf := range strings.Split(f, ",") { |
|
|
if f = strings.TrimSpace(f); f != "" { |
|
|
if sf = textproto.TrimString(sf); sf != "" { |
|
|
h.Del(f) |
|
|
h.Del(sf) |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|