From d23b210f4ef6ac8684783b320855445ad1568e4c Mon Sep 17 00:00:00 2001 From: Ta-Ching Chen Date: Mon, 15 Oct 2018 14:17:18 +0800 Subject: [PATCH] Add X-Forwarded-Host to request header (#890) --- router/functionHandler.go | 54 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 52 insertions(+), 2 deletions(-) diff --git a/router/functionHandler.go b/router/functionHandler.go index 4b4839a6..35c06d28 100644 --- a/router/functionHandler.go +++ b/router/functionHandler.go @@ -19,8 +19,6 @@ package router import ( "bytes" "fmt" - "github.com/gorilla/mux" - "github.com/satori/go.uuid" "io/ioutil" "math/rand" "net" @@ -30,6 +28,9 @@ import ( "strings" "time" + "github.com/gorilla/mux" + "github.com/satori/go.uuid" + log "github.com/sirupsen/logrus" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -39,6 +40,11 @@ import ( "github.com/fission/fission/redis" ) +const ( + FORWARDED = "Forwarded" + X_FORWARDED_HOST = "X-Forwarded-Host" +) + type tsRoundTripperParams struct { timeout time.Duration timeoutExponent int @@ -99,6 +105,9 @@ func (roundTripper RetryingRoundTripper) RoundTrip(req *http.Request) (resp *htt var needExecutor, serviceUrlFromExecutor bool var serviceUrl *url.URL + // Set forwarded host header if not exists + addForwardedHostHeader(req) + // TODO: Keep? --> Needed for queries encoded in URL before they're stripped by the proxy var originalUrl url.URL originalUrl = *req.URL @@ -362,3 +371,44 @@ func getCanaryBackend(fnMetadatamap map[string]*metav1.ObjectMeta, fnWtDistribut return fnMetadatamap[fnName] } + +// addForwardedHostHeader add "forwarded host" to request header +func addForwardedHostHeader(req *http.Request) { + // for more detailed information, please visit: + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Forwarded + + if len(req.Header.Get(FORWARDED)) > 0 || len(req.Header.Get(X_FORWARDED_HOST)) > 0 { + // forwarded headers were set by external proxy, leave them intact + return + } + + // Format of req.Host is : + // We need to extract hostname from it, than + // check whether a host is ipv4 or ipv6 or FQDN + reqUrl := fmt.Sprintf("%s://%s", req.Proto, req.Host) + u, err := url.Parse(reqUrl) + if err != nil { + log.Printf("Error parsing request url (%v): %v", reqUrl, err) + return + } + + var host string + + // ip will be nil if the Hostname is a FQDN string + ip := net.ParseIP(u.Hostname()) + + // ip == nil -> hostname is FQDN instead of ip address + // The order of To4() and To16() here matters, To16() will + // converts an IPv4 address to IPv6 format address and may + // cause router append wrong host value to header. To prevent + // this we need to check whether To4() is nil first. + if ip == nil || (ip != nil && ip.To4() != nil) { + host = fmt.Sprintf(`host=%s;`, req.Host) + } else if ip != nil && ip.To16() != nil { + // For the "Forwarded" header, if a host is an IPv6 address it should be quoted + host = fmt.Sprintf(`host="%s";`, req.Host) + } + + req.Header.Set(FORWARDED, host) + req.Header.Set(X_FORWARDED_HOST, req.Host) +}