package proxy import ( "net" "net/http" "net/url" "strings" "time" "github.com/rancher/wrangler/pkg/kubeconfig" utilnet "k8s.io/apimachinery/pkg/util/net" "k8s.io/apimachinery/pkg/util/proxy" "k8s.io/client-go/rest" "k8s.io/client-go/transport" ) // Mostly copied from "kubectl proxy" code func HandlerFromConfig(prefix, kubeConfig string) (http.Handler, error) { loader := kubeconfig.GetInteractiveClientConfig(kubeConfig) cfg, err := loader.ClientConfig() if err != nil { return nil, err } return Handler(prefix, cfg) } // Mostly copied from "kubectl proxy" code func Handler(prefix string, cfg *rest.Config) (http.Handler, error) { host := cfg.Host if !strings.HasSuffix(host, "/") { host = host + "/" } target, err := url.Parse(host) if err != nil { return nil, err } transport, err := rest.TransportFor(cfg) if err != nil { return nil, err } upgradeTransport, err := makeUpgradeTransport(cfg, 0) if err != nil { return nil, err } proxy := proxy.NewUpgradeAwareHandler(target, transport, false, false, er) proxy.UpgradeTransport = upgradeTransport proxy.UseRequestLocation = true handler := setHost(target.Host, proxy) if len(target.Path) > 1 { handler = prependPath(target.Path[:len(target.Path)-1], handler) } if len(prefix) > 2 { return stripLeaveSlash(prefix, handler), nil } return handler, nil } func setHost(host string, h http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { req.Host = host h.ServeHTTP(w, req) }) } func prependPath(prefix string, h http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { if len(req.URL.Path) > 1 { req.URL.Path = prefix + req.URL.Path } else { req.URL.Path = prefix } h.ServeHTTP(w, req) }) } // like http.StripPrefix, but always leaves an initial slash. (so that our // regexps will work.) func stripLeaveSlash(prefix string, h http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { p := strings.TrimPrefix(req.URL.Path, prefix) if len(p) >= len(req.URL.Path) { http.NotFound(w, req) return } if len(p) > 0 && p[:1] != "/" { p = "/" + p } req.URL.Path = p h.ServeHTTP(w, req) }) } func makeUpgradeTransport(config *rest.Config, keepalive time.Duration) (proxy.UpgradeRequestRoundTripper, error) { transportConfig, err := config.TransportConfig() if err != nil { return nil, err } tlsConfig, err := transport.TLSConfigFor(transportConfig) if err != nil { return nil, err } rt := utilnet.SetOldTransportDefaults(&http.Transport{ TLSClientConfig: tlsConfig, DialContext: (&net.Dialer{ Timeout: 30 * time.Second, KeepAlive: keepalive, }).DialContext, }) upgrader, err := transport.HTTPWrappersForConfig(transportConfig, proxy.MirrorRequest) if err != nil { return nil, err } return proxy.NewUpgradeRequestRoundTripper(rt, upgrader), nil }