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

Code before:
	r.targetResolver = nil

	r.proxyResolver.Close()
	r.proxyResolver = nil
}

// updateClientConnStateLocked creates a list of combined addresses by
// pairing each proxy address with every target address. For each pair, it
// generates a new [resolver.Address] using the proxy address, and adding the
// target address as the attribute along with user info. It returns nil if
// either resolver has not sent update even once and returns the error from
// ClientConn update once both resolvers have sent update atleast once.
func (r *delegatingResolver) updateClientConnStateLocked() error {
	if r.targetResolverState == nil {
		return nil
	}
	curState := *r.targetResolverState

	// Avoid proxy if networktype is not tcp.
	var networkType string
	var ok bool
	if len(curState.Endpoints) != 0 {
		networkType, ok = networktype.Get(curState.Endpoints[0].Addresses[0])
	} else {
		networkType, ok = networktype.Get(curState.Addresses[0])
	}
	// If the networktype is empty , or not present, tcp is considered as default.
	if ok && networkType != "tcp" {
		return r.cc.UpdateState(curState)
	}
	if r.proxyAddrs == nil { // Wait to get both resolver updates.
		return nil
	}

	// If multiple resolved proxy addresses are present, we send only the
	// unresolved proxy host and let net.Dial handle the proxy host name
	// resolution when creating the transport. Sending all resolved addresses
	// would increase the number of addresses passed to the ClientConn and
	// subsequently to load balancing (LB) policies like Round Robin, leading
	// to additional TCP connections. However, if there's only one resolved
	// proxy address, we send it directly, as it doesn't affect the address
	// count returned by the target resolver and the address count sent to the
	// ClientConn.
	var proxyAddr resolver.Address
	if len(r.proxyAddrs) == 1 {
		proxyAddr = r.proxyAddrs[0]
	} else {
		proxyAddr = resolver.Address{Addr: r.proxyURL.Host}
	}
	var addresses []resolver.Address
	for _, targetAddr := range (*r.targetResolverState).Addresses {

Review comment (refactor):
Here we're making an assumption that the network type of the first address of the endpoint is the same the address type of all remaining addresses. This may be true for most real-world usecases, but it isn't a requirement specified in the resolver API. It should not be too difficult to avoid proxying on a per-address basis. There are two places below where we do the following, one for `resolver.State.Addresses `and once for `resolver.State.Endpoints`:
```go
proxyattributes.Set(proxyAddr, proxyattributes.Options{
	User:        r.proxyURL.User,
	ConnectAddr: targetAddr.Addr,
})
```
We can refactor this into a method that takes in the target address and proxy address and returns the combined address.
```go
fn (r *delegatingResolver) combineAddresses(targetAddr, proxyAddr resolver.Address) resolver.Address {
    if  networktype.Get(targetAddr) != "tcp" {
        return targetAddr
    }
    return proxyattributes.Set(proxyAddr, proxyattributes.Options{
	User:        r.proxyURL.User,
	ConnectAddr: targetAddr.Addr,
    })
}

Code after:
}

func networkTypeFromAddr(addr resolver.Address) string {
	networkType, ok := networktype.Get(addr)
	if !ok {
		networkType, _ = transport.ParseDialTarget(addr.Addr)
	}
	return networkType
}

func isTCPAddressPresent(state *resolver.State) bool {
	for _, addr := range state.Addresses {
		if networkType := networkTypeFromAddr(addr); networkType == "tcp" {
			return true
		}
	}
	for _, endpoint := range state.Endpoints {
		for _, addr := range endpoint.Addresses {
			if networktype := networkTypeFromAddr(addr); networktype == "tcp" {
				return true
			}
		}
	}
	return false
}

// updateClientConnStateLocked constructs a combined list of addresses by
// pairing each proxy address with every target address of type TCP. For each
// pair, it creates a new [resolver.Address] using the proxy address and
// attaches the corresponding target address and user info as attributes. Target
// addresses that are not of type TCP are appended to the list as-is. The
// function returns nil if either resolver has not yet provided an update, and
// returns the result of ClientConn.UpdateState once both resolvers have
// provided at least one update.
func (r *delegatingResolver) updateClientConnStateLocked() error {
	if r.targetResolverState == nil || r.proxyAddrs == nil {
		return nil
	}

	// If multiple resolved proxy addresses are present, we send only the
	// unresolved proxy host and let net.Dial handle the proxy host name
	// resolution when creating the transport. Sending all resolved addresses
	// would increase the number of addresses passed to the ClientConn and
	// subsequently to load balancing (LB) policies like Round Robin, leading
	// to additional TCP connections. However, if there's only one resolved
	// proxy address, we send it directly, as it doesn't affect the address
	// count returned by the target resolver and the address count sent to the
	// ClientConn.
	var proxyAddr resolver.Address
	if len(r.proxyAddrs) == 1 {
		proxyAddr = r.proxyAddrs[0]