diff options
author | Brian Olson <brianolson@users.noreply.github.com> | 2021-07-07 17:25:58 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-07-07 17:25:58 -0400 |
commit | 3ac481ec2954a025c4e416fdb86696cda57829bb (patch) | |
tree | b362a2ff4e2239b201f4c768d14148989e4c51d8 | |
parent | f09d81419c2b939a6e2b1677ed805b17fcda6f37 (diff) |
allow to parse ipv6 localhost "[::]:4601" (#2430)dili
Allow parsing of ipv6 localhost -colon- port address.
"[::]:4601" was failing to parse. This and other forms pass ParseHostOrURL() now.
-rw-r--r-- | network/wsNetwork.go | 29 | ||||
-rw-r--r-- | network/wsNetwork_test.go | 50 |
2 files changed, 73 insertions, 6 deletions
diff --git a/network/wsNetwork.go b/network/wsNetwork.go index 21306eb34..49eacf331 100644 --- a/network/wsNetwork.go +++ b/network/wsNetwork.go @@ -1911,18 +1911,35 @@ var errBcastInvalidArray = errors.New("invalid broadcast array") var errBcastQFull = errors.New("broadcast queue full") -// HostColonPortPattern matches "^[^:]+:\\d+$" e.g. "foo.com.:1234" -var HostColonPortPattern = regexp.MustCompile("^[^:]+:\\d+$") +var errURLNoHost = errors.New("could not parse a host from url") + +// HostColonPortPattern matches "^[a-zA-Z0-9.]+:\\d+$" e.g. "foo.com.:1234" +var HostColonPortPattern = regexp.MustCompile("^[a-zA-Z0-9.]+:\\d+$") // ParseHostOrURL handles "host:port" or a full URL. // Standard library net/url.Parse chokes on "host:port". func ParseHostOrURL(addr string) (*url.URL, error) { - var parsedURL *url.URL + // If the entire addr is "host:port" grab that right away. + // Don't try url.Parse() because that will grab "host:" as if it were "scheme:" if HostColonPortPattern.MatchString(addr) { - parsedURL = &url.URL{Scheme: "http", Host: addr} - return parsedURL, nil + return &url.URL{Scheme: "http", Host: addr}, nil + } + parsed, err := url.Parse(addr) + if err == nil { + if parsed.Host == "" { + return nil, errURLNoHost + } + return parsed, nil + } + if strings.HasPrefix(addr, "http:") || strings.HasPrefix(addr, "https:") || strings.HasPrefix(addr, "ws:") || strings.HasPrefix(addr, "wss:") || strings.HasPrefix(addr, "://") || strings.HasPrefix(addr, "//") { + return parsed, err + } + // This turns "[::]:4601" into "http://[::]:4601" which url.Parse can do + parsed, e2 := url.Parse("http://" + addr) + if e2 == nil { + return parsed, nil } - return url.Parse(addr) + return parsed, err /* return original err, not our prefix altered try */ } // addrToGossipAddr parses host:port or a URL and returns the URL to the websocket interface at that address. diff --git a/network/wsNetwork_test.go b/network/wsNetwork_test.go index 1ccdfb0d1..e1670a7ba 100644 --- a/network/wsNetwork_test.go +++ b/network/wsNetwork_test.go @@ -24,6 +24,7 @@ import ( "math/rand" "net" "net/http" + "net/url" "os" "runtime" "sort" @@ -1969,3 +1970,52 @@ func BenchmarkVariableTransactionMessageBlockSizes(t *testing.B) { txnCount += txnCount/4 + 1 } } + +type urlCase struct { + text string + out url.URL +} + +func TestParseHostOrURL(t *testing.T) { + urlTestCases := []urlCase{ + {"localhost:123", url.URL{Scheme: "http", Host: "localhost:123"}}, + {"http://localhost:123", url.URL{Scheme: "http", Host: "localhost:123"}}, + {"ws://localhost:9999", url.URL{Scheme: "ws", Host: "localhost:9999"}}, + {"wss://localhost:443", url.URL{Scheme: "wss", Host: "localhost:443"}}, + {"https://localhost:123", url.URL{Scheme: "https", Host: "localhost:123"}}, + {"https://somewhere.tld", url.URL{Scheme: "https", Host: "somewhere.tld"}}, + {"http://127.0.0.1:123", url.URL{Scheme: "http", Host: "127.0.0.1:123"}}, + {"//somewhere.tld", url.URL{Scheme: "", Host: "somewhere.tld"}}, + {"//somewhere.tld:4601", url.URL{Scheme: "", Host: "somewhere.tld:4601"}}, + {"http://[::]:123", url.URL{Scheme: "http", Host: "[::]:123"}}, + {"1.2.3.4:123", url.URL{Scheme: "http", Host: "1.2.3.4:123"}}, + {"[::]:123", url.URL{Scheme: "http", Host: "[::]:123"}}, + } + badUrls := []string{ + "justahost", + "localhost:WAT", + "http://localhost:WAT", + "https://localhost:WAT", + "ws://localhost:WAT", + "wss://localhost:WAT", + "//localhost:WAT", + "://badaddress", // See rpcs/blockService_test.go TestRedirectFallbackEndpoints + "://localhost:1234", + } + for _, tc := range urlTestCases { + t.Run(tc.text, func(t *testing.T) { + v, err := ParseHostOrURL(tc.text) + require.NoError(t, err) + if tc.out != *v { + t.Errorf("url wanted %#v, got %#v", tc.out, v) + return + } + }) + } + for _, addr := range badUrls { + t.Run(addr, func(t *testing.T) { + _, err := ParseHostOrURL(addr) + require.Error(t, err, "url should fail", addr) + }) + } +} |