Skip to content

Commit

Permalink
Add support for Hostname(), Port() helpers
Browse files Browse the repository at this point in the history
  • Loading branch information
harshavardhana committed Apr 30, 2022
1 parent 3b76bda commit 2ffb566
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 0 deletions.
52 changes: 52 additions & 0 deletions net/url.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,58 @@ func (u URL) IsEmpty() bool {
return u.String() == ""
}

// validOptionalPort reports whether port is either an empty string
// or matches /^:\d*$/
func validOptionalPort(port string) bool {
if port == "" {
return true
}
if port[0] != ':' {
return false
}
for _, b := range port[1:] {
if b < '0' || b > '9' {
return false
}
}
return true
}

// splitHostPort separates host and port. If the port is not valid, it returns
// the entire input as host, and it doesn't check the validity of the host.
// Unlike net.SplitHostPort, but per RFC 3986, it requires ports to be numeric.
func splitHostPort(hostPort string) (host, port string) {
host = hostPort

colon := strings.LastIndexByte(host, ':')
if colon != -1 && validOptionalPort(host[colon:]) {
host, port = host[:colon], host[colon+1:]
}

if strings.HasPrefix(host, "[") && strings.HasSuffix(host, "]") {
host = host[1 : len(host)-1]
}

return
}

// Hostname returns u.Host, stripping any valid port number if present
//
// If the result is enclosed in square brackets, as literal IPv6 addresses are,
// the square brackets are removed from the result.
func (u URL) Hostname() string {
host, _ := splitHostPort(u.Host)
return host
}

// Port returns the port part of u.Host, without the leading colon.
//
// If u.Host doesn't contain a valid numeric port, Port returns an empty string.
func (u URL) Port() string {
_, port := splitHostPort(u.Host)
return port
}

// String - returns string representation of URL.
func (u URL) String() string {
// if port number 80 and 443, remove for http and https scheme respectively
Expand Down
44 changes: 44 additions & 0 deletions net/url_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,50 @@ import (
"testing"
)

func TestURLHostnameAndPort(t *testing.T) {
tests := []struct {
in string // URL.Host field
host string
port string
}{
{"foo.com:80", "foo.com", "80"},
{"foo.com", "foo.com", ""},
{"foo.com:", "foo.com", ""},
{"FOO.COM", "FOO.COM", ""}, // no canonicalization
{"1.2.3.4", "1.2.3.4", ""},
{"1.2.3.4:80", "1.2.3.4", "80"},
{"[1:2:3:4]", "1:2:3:4", ""},
{"[1:2:3:4]:80", "1:2:3:4", "80"},
{"[::1]:80", "::1", "80"},
{"[::1]", "::1", ""},
{"[::1]:", "::1", ""},
{"localhost", "localhost", ""},
{"localhost:443", "localhost", "443"},
{"some.super.long.domain.example.org:8080", "some.super.long.domain.example.org", "8080"},
{"[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:17000", "2001:0db8:85a3:0000:0000:8a2e:0370:7334", "17000"},
{"[2001:0db8:85a3:0000:0000:8a2e:0370:7334]", "2001:0db8:85a3:0000:0000:8a2e:0370:7334", ""},

// Ensure that even when not valid, Host is one of "Hostname",
// "Hostname:Port", "[Hostname]" or "[Hostname]:Port".
// See https://golang.org/issue/29098.
{"[minio.io]:80", "minio.io", "80"},
{"minio.io]:80", "minio.io]", "80"},
{"minio.io:80_invalid_port", "minio.io:80_invalid_port", ""},
{"[::1]extra]:80", "::1]extra", "80"},
{"minio.io]extra:extra", "minio.io]extra:extra", ""},
}
for _, tt := range tests {
u := URL{Host: tt.in}
host, port := u.Hostname(), u.Port()
if host != tt.host {
t.Errorf("Hostname for Host %q = %q; want %q", tt.in, host, tt.host)
}
if port != tt.port {
t.Errorf("Port for Host %q = %q; want %q", tt.in, port, tt.port)
}
}
}

func TestURLIsEmpty(t *testing.T) {
testCases := []struct {
url URL
Expand Down

0 comments on commit 2ffb566

Please sign in to comment.