// Connect returns a handler for the pod exec proxy func (r *AttachREST) Connect(ctx api.Context, name string, opts runtime.Object) (rest.ConnectHandler, error) { attachOpts, ok := opts.(*api.PodAttachOptions) if !ok { return nil, fmt.Errorf("Invalid options object: %#v", opts) } location, transport, err := pod.AttachLocation(r.store, r.kubeletConn, ctx, name, attachOpts) if err != nil { return nil, err } return genericrest.NewUpgradeAwareProxyHandler(location, transport, true), nil }
func (r *proxyHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { proxyRoundTripper, err := r.getRoundTripper() if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } if proxyRoundTripper == nil { http.Error(w, "", http.StatusNotFound) return } ctx, ok := r.contextMapper.Get(req) if !ok { http.Error(w, "missing context", http.StatusInternalServerError) return } user, ok := api.UserFrom(ctx) if !ok { http.Error(w, "missing user", http.StatusInternalServerError) return } // write a new location based on the existing request pointed at the target service location := &url.URL{} location.Scheme = "https" location.Host = r.getDestinationHost() location.Path = req.URL.Path location.RawQuery = req.URL.Query().Encode() // make a new request object with the updated location and the body we already have newReq, err := http.NewRequest(req.Method, location.String(), req.Body) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } mergeHeader(newReq.Header, req.Header) newReq.ContentLength = req.ContentLength // Copy the TransferEncoding is for future-proofing. Currently Go only supports "chunked" and // it can determine the TransferEncoding based on ContentLength and the Body. newReq.TransferEncoding = req.TransferEncoding upgrade := false // we need to wrap the roundtripper in another roundtripper which will apply the front proxy headers proxyRoundTripper = transport.NewAuthProxyRoundTripper(user.GetName(), user.GetGroups(), user.GetExtra(), proxyRoundTripper) proxyRoundTripper, upgrade, err = r.maybeWrapForConnectionUpgrades(proxyRoundTripper, req) handler := genericrest.NewUpgradeAwareProxyHandler(location, proxyRoundTripper, true, upgrade, &responder{w: w}) handler.ServeHTTP(w, newReq) }
func newUpgradeAwareProxyHandler(location *url.URL, transport http.RoundTripper, upgradeRequired bool) *genericrest.UpgradeAwareProxyHandler { handler := genericrest.NewUpgradeAwareProxyHandler(location, transport, upgradeRequired) handler.MaxBytesPerSec = capabilities.Get().PerConnectionBandwidthLimitBytesPerSec return handler }
func newThrottledUpgradeAwareProxyHandler(location *url.URL, transport http.RoundTripper, wrapTransport, upgradeRequired, interceptRedirects bool, responder rest.Responder) *genericrest.UpgradeAwareProxyHandler { handler := genericrest.NewUpgradeAwareProxyHandler(location, transport, wrapTransport, upgradeRequired, responder) handler.InterceptRedirects = interceptRedirects handler.MaxBytesPerSec = capabilities.Get().PerConnectionBandwidthLimitBytesPerSec return handler }
func (r *proxyHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { proxyRoundTripper, err := r.getRoundTripper() if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } if proxyRoundTripper == nil { http.Error(w, "", http.StatusNotFound) return } ctx, ok := r.contextMapper.Get(req) if !ok { http.Error(w, "missing context", http.StatusInternalServerError) return } user, ok := api.UserFrom(ctx) if !ok { http.Error(w, "missing user", http.StatusInternalServerError) return } // write a new location based on the existing request pointed at the target service location := &url.URL{} location.Scheme = "https" location.Host = r.getDestinationHost() location.Path = req.URL.Path location.RawQuery = req.URL.Query().Encode() // make a new request object with the updated location and the body we already have newReq, err := http.NewRequest(req.Method, location.String(), req.Body) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } mergeHeader(newReq.Header, req.Header) newReq.ContentLength = req.ContentLength // Copy the TransferEncoding is for future-proofing. Currently Go only supports "chunked" and // it can determine the TransferEncoding based on ContentLength and the Body. newReq.TransferEncoding = req.TransferEncoding upgrade := false // we need to wrap the roundtripper in another roundtripper which will apply the front proxy headers proxyRoundTripper, upgrade, err = r.maybeWrapForConnectionUpgrades(proxyRoundTripper, req) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } proxyRoundTripper = transport.NewAuthProxyRoundTripper(user.GetName(), user.GetGroups(), user.GetExtra(), proxyRoundTripper) // if we are upgrading, then the upgrade path tries to use this request with the TLS config we provide, but it does // NOT use the roundtripper. Its a direct call that bypasses the round tripper. This means that we have to // attach the "correct" user headers to the request ahead of time. After the initial upgrade, we'll be back // at the roundtripper flow, so we only have to muck with this request, but we do have to do it. if upgrade { transport.SetAuthProxyHeaders(newReq, user.GetName(), user.GetGroups(), user.GetExtra()) } handler := genericrest.NewUpgradeAwareProxyHandler(location, proxyRoundTripper, true, upgrade, &responder{w: w}) handler.ServeHTTP(w, newReq) }