Change:
// rewriteURL rewrites a single URL to go through the proxy, if the URL refers // to the same host as sourceURL, which is the page on which the target URL <del> // occurred. If any error occurs (e.g. parsing), it returns targetURL. func (t *Transport) rewriteURL(targetURL string, sourceURL *url.URL) string { </del> <ins> // occurred, or if the URL matches the sourceRequestHost. If any error occurs (e.g. // parsing), it returns targetURL. func (t *Transport) rewriteURL(targetURL string, sourceURL *url.URL, sourceRequestHost string) string { </ins> url, err := url.Parse(targetURL) if err != nil { return targetURL } <del> isDifferentHost := url.Host != "" && url.Host != sourceURL.Host </del> <ins> // Example: //      When API server processes a proxy request to a service (e.g. /api/v1/namespace/foo/service/bar/proxy/), //      the sourceURL.Host (i.e. req.URL.Host) is the endpoint IP address of the service. The //      sourceRequestHost (i.e. req.Host) is the Host header that specifies the host on which the //      URL is sought, which can be different from sourceURL.Host. For example, if user sends the //      request through "kubectl proxy" locally (i.e. localhost:8001/api/v1/namespace/foo/service/bar/proxy/), //      sourceRequestHost is "localhost:8001". // //      If the service's response URL contains non-empty host, and url.Host is equal to either sourceURL.Host //      or sourceRequestHost, we should not consider the returned URL to be a completely different host. //      It's the API server's responsibility to rewrite a same-host-and-absolute-path URL and append the //      necessary URL prefix (i.e. /api/v1/namespace/foo/service/bar/proxy/). isDifferentHost := url.Host != "" && url.Host != sourceURL.Host && url.Host != sourceRequestHost </ins> isRelative := !strings.HasPrefix(url.Path, "/") if isDifferentHost || isRelative { return targetURL } <del> url.Scheme = t.Scheme url.Host = t.Host </del> <ins> // Do not rewrite scheme and host if the Transport has empty scheme and host // when targetURL already contains the sourceRequestHost if !(url.Host == sourceRequestHost && t.Scheme == "" && t.Host == "") { url.Scheme = t.Scheme url.Host = t.Host } </ins> origPath := url.Path // Do not rewrite URL if the sourceURL already contains the necessary prefix. if strings.HasPrefix(url.Path, t.PathPrepend) {

Discussion:
<!-- This form is for bug reports and feature requests ONLY! If you're looking for help check and the . --Is this a BUG REPORT or FEATURE REQUEST?: What happened: When accessing a service (e.g., ) by using the Apiserver proxy feature and the service returns with header, such as The returned header does not preserve the path if the service sent a redirect with an absolute path. Depending on the cluster, the header written by the service itself might have been and the apiserver proxy did rewrite the host:port to match the correct values. Unfortunately, it did not rewrite the path segment. What you expected to happen: I would expect the apiserver to rewrite the path segment of the response header so that it reflects the fact that it's proxied under the path: How to reproduce it (as minimally and precisely as possible): The path was not preserved. Anything else we need to know?: To work around this issue, a service may return strictly a relative url in the header such as: The feature to rewrite headers is quite common. For instance, Apache Httpd does it thanks to: Environment: Kubernetes version (use ):Cloud provider or hardware configuration**: custom_ OS (e.g. from /etc/os-release): Kernel (e.g. ):
/sig api-machinery /sig network
/assign
Thanks for the bug report!
GitHub didn't allow me to assign the following users: roycaihw. Note that only can be assigned. <detailsIn response to : /assign Instructions for interacting with me using PR comments are available . If you have questions or suggestions related to my behavior, please file an issue against the repository. </details