in main.go [194:283]
func buildProxy(host, bind *url.URL, tokenSource oauth2.TokenSource, enableHttp2 bool, caCertificate *x509.Certificate) *httputil.ReverseProxy {
// Build and configure the proxy.
proxy := httputil.NewSingleHostReverseProxy(host)
// Use http2 for outgoing connections
if enableHttp2 {
var tlsConfig *tls.Config
if caCertificate != nil {
caPool := x509.NewCertPool()
caPool.AddCert(caCertificate)
tlsConfig = &tls.Config{
RootCAs: caPool,
}
}
proxy.Transport = &http2.Transport{
TLSClientConfig: tlsConfig,
}
}
// Configure the director.
originalDirector := proxy.Director
proxy.Director = func(r *http.Request) {
// Call the original director, which configures most of the URL bits for us.
originalDirector(r)
// Override host - this is not done by the default director, but Cloud Run
// requires it.
r.Header.Set("Host", host.Host)
r.Host = host.Host
ctx := r.Context()
// Get the oauth token.
token, err := tokenSource.Token()
if err != nil {
*r = *r.WithContext(context.WithValue(ctx, contextKeyError,
fmt.Errorf("failed to get token: %w\n\n%s", err, ADCHintMessage)))
return
}
// Get the id_token.
idToken := token.AccessToken
if idToken == "" {
*r = *r.WithContext(context.WithValue(ctx, contextKeyError,
fmt.Errorf("missing id_token")))
return
}
// Set a custom user-agent header.
if *flagPrependUserAgent {
ua := r.Header.Get("User-Agent")
if ua == "" {
ua = userAgent
} else {
ua = userAgent + " " + ua
}
r.Header.Set("User-Agent", ua)
}
// Set the bearer token to be the id token
r.Header.Set(*flagAuthorizationHeader, "Bearer "+idToken)
}
// Configure error handling.
proxy.ModifyResponse = func(r *http.Response) error {
// In case of redirection, make sure the local address is still used for
// host. If it has location header && the location url host is the proxied
// host, change it to local address with http.
location := r.Header.Get("Location")
if location != "" {
locationURL, err := url.Parse(location)
if err == nil && locationURL.Host == host.Host {
locationURL.Scheme = bind.Scheme
locationURL.Host = bind.Host
r.Header.Set("Location", locationURL.String())
}
}
ctx := r.Request.Context()
if err, ok := ctx.Value(contextKeyError).(error); ok && err != nil {
return fmt.Errorf("[PROXY ERROR] %w", err)
}
return nil
}
proxy.ErrorHandler = func(w http.ResponseWriter, r *http.Request, err error) {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
return proxy
}