Skip to content

Commit

Permalink
added header based proxy support
Browse files Browse the repository at this point in the history
  • Loading branch information
ins-tykgw committed Feb 5, 2021
1 parent 61ba853 commit 0e55720
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 1 deletion.
4 changes: 3 additions & 1 deletion apidef/api_definitions.go
Original file line number Diff line number Diff line change
Expand Up @@ -508,7 +508,9 @@ type RequestSigningMeta struct {
}

type ProxyConfig struct {
PreserveHostHeader bool `bson:"preserve_host_header" json:"preserve_host_header"`
PreserveHostHeader bool `bson:"preserve_host_header" json:"preserve_host_header"`
//Cisco - enable host re-write from header
UpdateHostHeader string `bson:"update_host_header" json:"update_host_header"`
ListenPath string `bson:"listen_path" json:"listen_path"`
TargetURL string `bson:"target_url" json:"target_url"`
DisableStripSlash bool `bson:"disable_strip_slash" json:"disable_strip_slash"`
Expand Down
78 changes: 78 additions & 0 deletions gateway/handler_success.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,15 @@ package gateway

import (
"bytes"
"crypto/tls"
"encoding/base64"
"io"
"io/ioutil"
"net"
"net/http"
"net/http/httputil"
"net/textproto"
"net/url"
"runtime/pprof"
"strconv"
"strings"
Expand Down Expand Up @@ -304,6 +309,52 @@ func (s *SuccessHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) *http
log.Debug("Started proxy")
defer s.Base().UpdateRequestSession(r)

log.Debug("Check update_host_header")
if len(s.Spec.Proxy.UpdateHostHeader) > 0 {
//Normalize header
log.Debug("Detected UpdateHostHeader ", s.Spec.Proxy.UpdateHostHeader)
header := textproto.CanonicalMIMEHeaderKey(s.Spec.Proxy.UpdateHostHeader)
log.Debug("CanonicalMIMEHeaderKey form ", s.Spec.Proxy.UpdateHostHeader)
updateHost, ok := r.Header[header]
if ok {
//Create Reverse proxy
director := func(req *http.Request) {
req.Header.Del(header)
log.Debug("Updating upstream host", updateHost[0])

//Set host
req.URL.Host = updateHost[0]

targetUrl, _ := url.Parse(s.Spec.Proxy.TargetURL)

//Set Scheme
switch targetUrl.Scheme {
case "http":
req.URL.Scheme = "http"
case "https":
req.URL.Scheme = "https"
case "ws":
req.URL.Scheme = "http"
case "wss":
req.URL.Scheme = "https"
}

//Reset the rawquery assuming URLRewrite may have reset the path
if origURL := ctxGetOrigRequestURL(r); origURL != nil {
req.URL.RawQuery = origURL.RawQuery
}
}

proxy := &httputil.ReverseProxy{Director: director}
proxy.Transport = defaultProxyTransport(30)

log.Debug("Start update_host_header proxy")
proxy.ServeHTTP(w, r)
log.Debug("Done update_host_header proxy")
return nil
}
}

versionDef := s.Spec.VersionDefinition
if !s.Spec.VersionData.NotVersioned && versionDef.Location == "url" && versionDef.StripPath {
part := s.Spec.getVersionFromRequest(r)
Expand Down Expand Up @@ -341,6 +392,33 @@ func (s *SuccessHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) *http
return nil
}

func defaultProxyTransport(dialerTimeout float64) http.RoundTripper {
timeout := 30.0
if dialerTimeout > 0 {
log.Debug("Setting timeout for outbound request to: ", dialerTimeout)
timeout = dialerTimeout
}

dialer := &net.Dialer{
Timeout: time.Duration(float64(timeout) * float64(time.Second)),
KeepAlive: 30 * time.Second,
DualStack: true,
}
dialContextFunc := dialer.DialContext
if dnsCacheManager.IsCacheEnabled() {
dialContextFunc = dnsCacheManager.WrapDialer(dialer)
}

return &http.Transport{
DialContext: dialContextFunc,
MaxIdleConns: config.Global().MaxIdleConns,
MaxIdleConnsPerHost: config.Global().MaxIdleConnsPerHost, // default is 100
ResponseHeaderTimeout: time.Duration(dialerTimeout) * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}
}

// ServeHTTPWithCache will store the request details in the analytics store if necessary and proxy the request to it's
// final destination, this is invoked by the ProxyHandler or right at the start of a request chain if the URL
// Spec states the path is Ignored Itwill also return a response object for the cache
Expand Down
14 changes: 14 additions & 0 deletions gateway/reverse_proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"net"
"net/http"
"net/http/httptest"
"net/textproto"
"net/url"
"strconv"
"strings"
Expand Down Expand Up @@ -279,6 +280,19 @@ func TykNewSingleHostReverseProxy(target *url.URL, spec *APISpec, logger *logrus
req.Host = targetToUse.Host
}

//Cisco change
if len(spec.Proxy.UpdateHostHeader) > 0 {
//Normalize header
log.Debug("Detected UpdateHostHeader ", spec.Proxy.UpdateHostHeader)
header := textproto.CanonicalMIMEHeaderKey(spec.Proxy.UpdateHostHeader)
log.Debug("CanonicalMIMEHeaderKey form ", spec.Proxy.UpdateHostHeader)
updateHost, ok := req.Header[header]
if ok {
log.Debug("Updating upstream host", updateHost[0])
req.Host = updateHost[0]
}
}

if targetQuery == "" || req.URL.RawQuery == "" {
req.URL.RawQuery = targetQuery + req.URL.RawQuery
} else {
Expand Down

0 comments on commit 0e55720

Please sign in to comment.