summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrian Olson <brianolson@users.noreply.github.com>2021-07-07 17:25:58 -0400
committerGitHub <noreply@github.com>2021-07-07 17:25:58 -0400
commit3ac481ec2954a025c4e416fdb86696cda57829bb (patch)
treeb362a2ff4e2239b201f4c768d14148989e4c51d8
parentf09d81419c2b939a6e2b1677ed805b17fcda6f37 (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.go29
-rw-r--r--network/wsNetwork_test.go50
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)
+ })
+ }
+}