diff --git a/url.go b/url.go index 4db586f..05147d4 100644 --- a/url.go +++ b/url.go @@ -2,6 +2,7 @@ package honeybee import ( "net/url" + "strings" "git.wisehodl.dev/jay/go-honeybee/errors" ) @@ -18,3 +19,22 @@ func ParseURL(urlStr string) (*url.URL, error) { return parsedURL, nil } + +func NormalizeURL(input string) (string, error) { + parsed, err := ParseURL(strings.ToLower(input)) + if err != nil { + return "", err + } + + host := parsed.Hostname() + port := parsed.Port() + if (parsed.Scheme == "wss" && port == "443") || + (parsed.Scheme == "ws" && port == "80") { + parsed.Host = host + } + + parsed.Path = strings.TrimRight(parsed.Path, "/") + + return parsed.String(), nil + +} diff --git a/url_test.go b/url_test.go index be59986..933d327 100644 --- a/url_test.go +++ b/url_test.go @@ -91,3 +91,75 @@ func TestParseURL(t *testing.T) { }) } } + +func TestNormalizeURL(t *testing.T) { + cases := []struct { + name string + input string + expected string + }{ + { + name: "strip trailing slash", + input: "wss://relay.example.com/", + expected: "wss://relay.example.com", + }, + { + name: "strip multiple trailing slashes", + input: "wss://relay.example.com//", + expected: "wss://relay.example.com", + }, + { + name: "strip trailing slash with path", + input: "wss://relay.example.com/path/", + expected: "wss://relay.example.com/path", + }, + { + name: "lowercase scheme", + input: "WSS://relay.example.com", + expected: "wss://relay.example.com", + }, + { + name: "lowercase host", + input: "wss://Relay.Example.Com", + expected: "wss://relay.example.com", + }, + { + name: "strip default wss port", + input: "wss://relay.example.com:443", + expected: "wss://relay.example.com", + }, + { + name: "strip default ws port", + input: "ws://relay.example.com:80", + expected: "ws://relay.example.com", + }, + { + name: "preserve non-default port", + input: "wss://relay.example.com:8080", + expected: "wss://relay.example.com:8080", + }, + { + name: "preserve path", + input: "wss://relay.example.com/nostr", + expected: "wss://relay.example.com/nostr", + }, + { + name: "no change needed", + input: "wss://relay.example.com", + expected: "wss://relay.example.com", + }, + } + + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + got, err := NormalizeURL(tc.input) + assert.NoError(t, err) + assert.Equal(t, tc.expected, got) + }) + } +} + +func TestNormalizeURLError(t *testing.T) { + _, err := NormalizeURL("http://relay.example.com") + assert.ErrorIs(t, err, errors.InvalidProtocol) +}