Repository: grpc/grpc-go
File: internal/resolver/delegatingresolver/delegatingresolver.go (Go)

Code before:
}

// New creates a new delegating resolver that can create up to two child
// resolvers:
//   - one to resolve the proxy address specified using the supported
//     environment variables. This uses the registered resolver for the "dns"
//     scheme. It is lazily built when a target resolver update contains at least
//     one TCP address.
//   - one to resolve the target URI using the resolver specified by the scheme
//     in the target URI or specified by the user using the WithResolvers dial
//     option. As a special case, if the target URI's scheme is "dns" and a
//     proxy is specified using the supported environment variables, the target
//     URI's path portion is used as the resolved address unless target
//     resolution is enabled using the dial option.
func New(target resolver.Target, cc resolver.ClientConn, opts resolver.BuildOptions, targetResolverBuilder resolver.Builder, targetResolutionEnabled bool) (resolver.Resolver, error) {
	r := &delegatingResolver{
		target:         target,
		cc:             cc,
		proxyResolver:  nopResolver{},
		targetResolver: nopResolver{},
	}

	addr, err := parseTarget(target.Endpoint())
	if err != nil {
		return nil, fmt.Errorf("delegating_resolver: invalid target address %q: %v", target.Endpoint(), err)
	}
	r.proxyURL, err = proxyURLForTarget(addr)
	if err != nil {
		return nil, fmt.Errorf("delegating_resolver: failed to determine proxy URL for target %q: %v", target, err)
	}

	// proxy is not configured or proxy address excluded using `NO_PROXY` env
	// var, so only target resolver is used.
	if r.proxyURL == nil {
		return targetResolverBuilder.Build(target, cc, opts)
	}

	if logger.V(2) {
		logger.Infof("Proxy URL detected : %s", r.proxyURL)
	}

	// Resolver updates from one child may trigger calls into the other. Block
	// updates until the children are initialized.
	r.childMu.Lock()
	defer r.childMu.Unlock()
	// When the scheme is 'dns' and target resolution on client is not enabled,
	// resolution should be handled by the proxy, not the client. Therefore, we
	// bypass the target resolver and store the unresolved target address.
	if target.URL.Scheme == "dns" && !targetResolutionEnabled {
		addr := target.Endpoint()
		if envconfig.AddDefaultPort {

Review comment (bug):
I think we should guard this call to `parseTarget` behind the feature flag since it can potentially lead to new/different failures after this PR is merged.

Code after:
}

// New creates a new delegating resolver that can create up to two child
// resolvers:
//   - one to resolve the proxy address specified using the supported
//     environment variables. This uses the registered resolver for the "dns"
//     scheme. It is lazily built when a target resolver update contains at least
//     one TCP address.
//   - one to resolve the target URI using the resolver specified by the scheme
//     in the target URI or specified by the user using the WithResolvers dial
//     option. As a special case, if the target URI's scheme is "dns" and a
//     proxy is specified using the supported environment variables, the target
//     URI's path portion is used as the resolved address unless target
//     resolution is enabled using the dial option.
func New(target resolver.Target, cc resolver.ClientConn, opts resolver.BuildOptions, targetResolverBuilder resolver.Builder, targetResolutionEnabled bool) (resolver.Resolver, error) {
	r := &delegatingResolver{
		target:         target,
		cc:             cc,
		proxyResolver:  nopResolver{},
		targetResolver: nopResolver{},
	}

	addr := target.Endpoint()
	var err error
	if target.URL.Scheme == "dns" && !targetResolutionEnabled && envconfig.EnableDefaultPortForProxyTarget {
		addr, err = parseTarget(addr)
		if err != nil {
			return nil, fmt.Errorf("delegating_resolver: invalid target address %q: %v", target.Endpoint(), err)
		}
	}

	r.proxyURL, err = proxyURLForTarget(addr)
	if err != nil {
		return nil, fmt.Errorf("delegating_resolver: failed to determine proxy URL for target %q: %v", target, err)
	}

	// proxy is not configured or proxy address excluded using `NO_PROXY` env
	// var, so only target resolver is used.
	if r.proxyURL == nil {
		return targetResolverBuilder.Build(target, cc, opts)
	}

	if logger.V(2) {
		logger.Infof("Proxy URL detected : %s", r.proxyURL)
	}

	// Resolver updates from one child may trigger calls into the other. Block
	// updates until the children are initialized.
	r.childMu.Lock()
	defer r.childMu.Unlock()
	// When the scheme is 'dns' and target resolution on client is not enabled,