From a73238843e42a6142db7a8e95466a35a09fd5036 Mon Sep 17 00:00:00 2001 From: evan-forbes Date: Fri, 15 Nov 2024 08:52:43 -0600 Subject: [PATCH 1/5] fix: rpc "no port provided" error by backporting https://github.com/cometbft/cometbft/pull/1903 --- rpc/jsonrpc/client/http_json_client.go | 14 +++++++++++++- rpc/jsonrpc/client/http_json_client_test.go | 19 ++++++++++++++++--- 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/rpc/jsonrpc/client/http_json_client.go b/rpc/jsonrpc/client/http_json_client.go index 76fa5063f9..864d04eb97 100644 --- a/rpc/jsonrpc/client/http_json_client.go +++ b/rpc/jsonrpc/client/http_json_client.go @@ -9,6 +9,7 @@ import ( "net" "net/http" "net/url" + "regexp" "strings" cmtsync "github.com/tendermint/tendermint/libs/sync" @@ -24,7 +25,7 @@ const ( protoUNIX = "unix" ) -//------------------------------------------------------------- +var endsWithPortPattern = regexp.MustCompile(`:[0-9]+$`) // Parsed URL structure type parsedURL struct { @@ -91,6 +92,17 @@ func (u parsedURL) GetTrimmedHostWithPath() string { func (u parsedURL) GetDialAddress() string { // if it's not a unix socket we return the host, example: localhost:443 if !u.isUnixSocket { + hasPort := endsWithPortPattern.MatchString(u.Host) + if !hasPort { + // http and ws default to port 80, https and wss default to port 443 + // https://www.rfc-editor.org/rfc/rfc9110#section-4.2 + // https://www.rfc-editor.org/rfc/rfc6455.html#section-3 + if u.Scheme == protoHTTP || u.Scheme == protoWS { + return u.Host + `:80` + } else if u.Scheme == protoHTTPS || u.Scheme == protoWSS { + return u.Host + `:443` + } + } return u.Host } // otherwise we return the path of the unix socket, ex /tmp/socket diff --git a/rpc/jsonrpc/client/http_json_client_test.go b/rpc/jsonrpc/client/http_json_client_test.go index 03134dff58..c2a722141b 100644 --- a/rpc/jsonrpc/client/http_json_client_test.go +++ b/rpc/jsonrpc/client/http_json_client_test.go @@ -44,6 +44,19 @@ func Test_parsedURL(t *testing.T) { } tests := map[string]test{ + "http endpoint": { + url: "http://example.com", + expectedURL: "http://example.com", + expectedHostWithPath: "example.com", + expectedDialAddress: "example.com:80", + }, + + "http endpoint with port": { + url: "http://example.com:8080", + expectedURL: "http://example.com:8080", + expectedHostWithPath: "example.com:8080", + expectedDialAddress: "example.com:8080", + }, "unix endpoint": { url: "unix:///tmp/test", expectedURL: "unix://.tmp.test", @@ -51,21 +64,21 @@ func Test_parsedURL(t *testing.T) { expectedDialAddress: "/tmp/test", }, - "http endpoint": { + "https endpoint": { url: "https://example.com", expectedURL: "https://example.com", expectedHostWithPath: "example.com", expectedDialAddress: "example.com", }, - "http endpoint with port": { + "https endpoint with port": { url: "https://example.com:8080", expectedURL: "https://example.com:8080", expectedHostWithPath: "example.com:8080", expectedDialAddress: "example.com:8080", }, - "http path routed endpoint": { + "https path routed endpoint": { url: "https://example.com:8080/rpc", expectedURL: "https://example.com:8080/rpc", expectedHostWithPath: "example.com:8080/rpc", From 66068e462a4044ef1b5aff5f0464b857ffbb33cf Mon Sep 17 00:00:00 2001 From: evan-forbes Date: Fri, 15 Nov 2024 12:26:28 -0600 Subject: [PATCH 2/5] chore: try slightly different fix to support existing e2e test --- rpc/jsonrpc/client/http_json_client.go | 29 ++++++++++++++------------ 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/rpc/jsonrpc/client/http_json_client.go b/rpc/jsonrpc/client/http_json_client.go index 864d04eb97..ad1dc7a422 100644 --- a/rpc/jsonrpc/client/http_json_client.go +++ b/rpc/jsonrpc/client/http_json_client.go @@ -88,24 +88,27 @@ func (u parsedURL) GetTrimmedHostWithPath() string { return strings.ReplaceAll(u.GetHostWithPath(), "/", ".") } -// GetDialAddress returns the endpoint to dial for the parsed URL +// GetDialAddress returns the endpoint to dial for the parsed URL. func (u parsedURL) GetDialAddress() string { - // if it's not a unix socket we return the host, example: localhost:443 if !u.isUnixSocket { - hasPort := endsWithPortPattern.MatchString(u.Host) - if !hasPort { - // http and ws default to port 80, https and wss default to port 443 - // https://www.rfc-editor.org/rfc/rfc9110#section-4.2 - // https://www.rfc-editor.org/rfc/rfc6455.html#section-3 - if u.Scheme == protoHTTP || u.Scheme == protoWS { - return u.Host + `:80` - } else if u.Scheme == protoHTTPS || u.Scheme == protoWSS { - return u.Host + `:443` + host := u.Host + // Check if the host already includes a port + _, _, err := net.SplitHostPort(host) + if err != nil { + // Add the default port based on the scheme + switch u.Scheme { + case protoHTTP, protoWS: + host = net.JoinHostPort(host, "80") + case protoHTTPS, protoWSS: + host = net.JoinHostPort(host, "443") + default: + // Handle unsupported schemes explicitly + panic("unsupported scheme: " + u.Scheme) } } - return u.Host + return host } - // otherwise we return the path of the unix socket, ex /tmp/socket + // For Unix sockets, return the full path return u.GetHostWithPath() } From 39275ecf2f482f0097af316b25f12ca7fceb4605 Mon Sep 17 00:00:00 2001 From: evan-forbes Date: Fri, 15 Nov 2024 13:58:17 -0600 Subject: [PATCH 3/5] fix: linter --- rpc/jsonrpc/client/http_json_client.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/rpc/jsonrpc/client/http_json_client.go b/rpc/jsonrpc/client/http_json_client.go index ad1dc7a422..ff5cfd6580 100644 --- a/rpc/jsonrpc/client/http_json_client.go +++ b/rpc/jsonrpc/client/http_json_client.go @@ -9,7 +9,6 @@ import ( "net" "net/http" "net/url" - "regexp" "strings" cmtsync "github.com/tendermint/tendermint/libs/sync" @@ -25,8 +24,6 @@ const ( protoUNIX = "unix" ) -var endsWithPortPattern = regexp.MustCompile(`:[0-9]+$`) - // Parsed URL structure type parsedURL struct { url.URL From a8da43221e03e99c60255da4ddbfe86c6c559898 Mon Sep 17 00:00:00 2001 From: evan-forbes Date: Fri, 15 Nov 2024 14:01:06 -0600 Subject: [PATCH 4/5] fix: test --- rpc/jsonrpc/client/http_json_client_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rpc/jsonrpc/client/http_json_client_test.go b/rpc/jsonrpc/client/http_json_client_test.go index c2a722141b..86a13acb8b 100644 --- a/rpc/jsonrpc/client/http_json_client_test.go +++ b/rpc/jsonrpc/client/http_json_client_test.go @@ -68,7 +68,7 @@ func Test_parsedURL(t *testing.T) { url: "https://example.com", expectedURL: "https://example.com", expectedHostWithPath: "example.com", - expectedDialAddress: "example.com", + expectedDialAddress: "example.com:443", }, "https endpoint with port": { From 67834a239ba84f8460dcdb94a5f4bc687ffc9f96 Mon Sep 17 00:00:00 2001 From: evan-forbes Date: Sat, 16 Nov 2024 13:13:54 -0600 Subject: [PATCH 5/5] chore: try with IPv6 fix --- rpc/jsonrpc/client/http_json_client.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/rpc/jsonrpc/client/http_json_client.go b/rpc/jsonrpc/client/http_json_client.go index ff5cfd6580..fce584cb73 100644 --- a/rpc/jsonrpc/client/http_json_client.go +++ b/rpc/jsonrpc/client/http_json_client.go @@ -85,7 +85,6 @@ func (u parsedURL) GetTrimmedHostWithPath() string { return strings.ReplaceAll(u.GetHostWithPath(), "/", ".") } -// GetDialAddress returns the endpoint to dial for the parsed URL. func (u parsedURL) GetDialAddress() string { if !u.isUnixSocket { host := u.Host @@ -103,9 +102,8 @@ func (u parsedURL) GetDialAddress() string { panic("unsupported scheme: " + u.Scheme) } } - return host + return "[" + host + "]" // Explicitly wrap IPv6 addresses in brackets } - // For Unix sockets, return the full path return u.GetHostWithPath() }