redis / go-redis

Redis Go client
https://redis.uptrace.dev
BSD 2-Clause "Simplified" License
19.6k stars 2.31k forks source link

Handle IPv6 in isMovedError #2981

Closed daviddzxy closed 2 months ago

daviddzxy commented 2 months ago

If the address in the error is an IPv6 address it adds squared brackets around the host part of the address.

monkey92t commented 2 months ago

should:

func getAddr(addr string) string {
    ind := strings.LastIndex(addr, ":")
    if ind == -1 {
        return ""
    }

    if string(addr[ind-1]) == "]" {
        return ""
    }

    return net.JoinHostPort(addr[:ind], addr[ind+1:])
}

func TestAddr(t *testing.T) {
    if v := getAddr("127.0.0.1:1234"); v != "127.0.0.1:1234" {
        t.Fatalf("getAddr failed: %v", v)
    }
    if v := getAddr("[::1]:1234"); v != "[::1]:1234" {
        t.Fatalf("getAddr failed: %v", v)
    }
    if v := getAddr("::1:1234"); v != "[::1]:1234" {
        t.Fatalf("getAddr failed: %v", v)
    }
    if v := getAddr("fd01:abcd::7d03:6379"); v != "[fd01:abcd::7d03]:6379" {
        t.Fatalf("getAddr failed: %v", v)
    }
    if v := getAddr("[fd01:abcd::7d03]:6379"); v != "[fd01:abcd::7d03]:6379" {
        t.Fatalf("getAddr failed: %v", v)
    }
    if v := getAddr("127.0.0.1"); v != "" {
        t.Fatalf("getAddr failed: %v", v)
    }
    if v := getAddr("127"); v != "" {
        t.Fatalf("getAddr failed: %v", v)
    }
}
monkey92t commented 2 months ago

There were some errors in the unit tests, but I have already fixed them.

daviddzxy commented 2 months ago

I moved the GetAddr function into internal/util.go and unit tests were moved to internal/util_test.go. What do you think?

monkey92t commented 2 months ago

In the current scenario, we should trust the validity of the data returned by the redis-server. It is known that the redis-server may return three types of data: 127.0.0.1:6379 (IPv4), ::1:6379 (incorrect IPv6), [::1]:6379 (correct IPv6).

monkey92t commented 2 months ago
func getAddr(addr string) string {
    idx := strings.LastIndexByte(addr, ':')
    if idx == -1 {
        return ""
    }

    // ipv4
    if strings.IndexByte(addr, '.') != -1 {
        return addr
    }

    // ipv6
    if addr[0] == '[' {
        return addr
    }
    return net.JoinHostPort(addr[:idx], addr[idx+1:])
}
monkey92t commented 2 months ago

Both LastIndex() and Index() are complex functions that search for one string within another string, rather than searching for a single character. This is a completely different approach. In the current situation, we only need to search for a single character, not a string.

callmeadi commented 1 month ago

When are we releasing a tagged version for this? @daviddzxy @monkey92t