mirror of
https://github.com/vmware-tanzu/pinniped.git
synced 2025-12-23 06:15:47 +00:00
348 lines
11 KiB
Go
348 lines
11 KiB
Go
// Copyright 2021-2024 the Pinniped contributors. All Rights Reserved.
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
package endpointaddr
|
|
|
|
import (
|
|
"net/url"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestParse(t *testing.T) {
|
|
t.Parallel()
|
|
for _, tt := range []struct {
|
|
name string
|
|
input string
|
|
defaultPort uint16
|
|
expectErr string
|
|
expect HostPort
|
|
expectEndpoint string
|
|
}{
|
|
{
|
|
name: "plain IPv4",
|
|
input: "127.0.0.1",
|
|
defaultPort: 443,
|
|
expect: HostPort{Host: "127.0.0.1", Port: 443},
|
|
expectEndpoint: "127.0.0.1:443",
|
|
},
|
|
{
|
|
name: "IPv4 with port",
|
|
input: "127.0.0.1:8443",
|
|
defaultPort: 443,
|
|
expect: HostPort{Host: "127.0.0.1", Port: 8443},
|
|
expectEndpoint: "127.0.0.1:8443",
|
|
},
|
|
{
|
|
name: "IPv4 in brackets with port",
|
|
input: "[127.0.0.1]:8443",
|
|
defaultPort: 443,
|
|
expect: HostPort{Host: "127.0.0.1", Port: 8443},
|
|
expectEndpoint: "127.0.0.1:8443",
|
|
},
|
|
{
|
|
name: "invalid IPv4",
|
|
input: "1.1.1.",
|
|
defaultPort: 443,
|
|
expectErr: `host "1.1.1." is not a valid hostname or IP address`,
|
|
},
|
|
{
|
|
name: "IPv4 as IPv6 in brackets with port",
|
|
input: "[::127.0.0.1]:8443",
|
|
defaultPort: 443,
|
|
expect: HostPort{Host: "::127.0.0.1", Port: 8443},
|
|
expectEndpoint: "[::127.0.0.1]:8443",
|
|
},
|
|
{
|
|
name: "IPv4 as IPv6 without port",
|
|
input: "::127.0.0.1",
|
|
defaultPort: 443,
|
|
expect: HostPort{Host: "::127.0.0.1", Port: 443},
|
|
expectEndpoint: "[::127.0.0.1]:443",
|
|
},
|
|
{
|
|
name: "plain IPv6 without port",
|
|
input: "2001:db8::ffff",
|
|
defaultPort: 443,
|
|
expect: HostPort{Host: "2001:db8::ffff", Port: 443},
|
|
expectEndpoint: "[2001:db8::ffff]:443",
|
|
},
|
|
{
|
|
name: "IPv6 with port",
|
|
input: "[2001:db8::ffff]:8443",
|
|
defaultPort: 443,
|
|
expect: HostPort{Host: "2001:db8::ffff", Port: 8443},
|
|
expectEndpoint: "[2001:db8::ffff]:8443",
|
|
},
|
|
{
|
|
name: "plain hostname",
|
|
input: "host.example.com",
|
|
defaultPort: 443,
|
|
expect: HostPort{Host: "host.example.com", Port: 443},
|
|
expectEndpoint: "host.example.com:443",
|
|
},
|
|
{
|
|
name: "plain hostname with dash",
|
|
input: "host-dev.example.com",
|
|
defaultPort: 443,
|
|
expect: HostPort{Host: "host-dev.example.com", Port: 443},
|
|
expectEndpoint: "host-dev.example.com:443",
|
|
},
|
|
{
|
|
name: "hostname with port",
|
|
input: "host.example.com:8443",
|
|
defaultPort: 443,
|
|
expect: HostPort{Host: "host.example.com", Port: 8443},
|
|
expectEndpoint: "host.example.com:8443",
|
|
},
|
|
{
|
|
name: "hostname in brackets with port",
|
|
input: "[host.example.com]:8443",
|
|
defaultPort: 443,
|
|
expect: HostPort{Host: "host.example.com", Port: 8443},
|
|
expectEndpoint: "host.example.com:8443",
|
|
},
|
|
{
|
|
name: "hostname without dots",
|
|
input: "localhost",
|
|
defaultPort: 443,
|
|
expect: HostPort{Host: "localhost", Port: 443},
|
|
expectEndpoint: "localhost:443",
|
|
},
|
|
{
|
|
name: "hostname and port without dots",
|
|
input: "localhost:8443",
|
|
defaultPort: 443,
|
|
expect: HostPort{Host: "localhost", Port: 8443},
|
|
expectEndpoint: "localhost:8443",
|
|
},
|
|
{
|
|
name: "invalid empty string",
|
|
input: "",
|
|
defaultPort: 443,
|
|
expectErr: `host "" is not a valid hostname or IP address`,
|
|
},
|
|
{
|
|
// IPv6 zone index specifiers are not yet supported.
|
|
name: "IPv6 with port and zone index",
|
|
input: "[2001:db8::ffff%lo0]:8443",
|
|
defaultPort: 443,
|
|
expectErr: `host "2001:db8::ffff%lo0" is not a valid hostname or IP address`,
|
|
},
|
|
{
|
|
name: "IPv6 in brackets without port",
|
|
input: "[2001:db8::ffff]",
|
|
defaultPort: 443,
|
|
expectErr: `address [[2001:db8::ffff]]:443: missing port in address`,
|
|
},
|
|
{
|
|
name: "invalid HTTPS URL",
|
|
input: "https://host.example.com",
|
|
defaultPort: 443,
|
|
expectErr: `invalid port "//host.example.com"`,
|
|
},
|
|
{
|
|
name: "invalid host with URL path",
|
|
input: "host.example.com/some/path",
|
|
defaultPort: 443,
|
|
expectErr: `host "host.example.com/some/path" is not a valid hostname or IP address`,
|
|
},
|
|
{
|
|
name: "invalid host with mismatched brackets",
|
|
input: "[host.example.com",
|
|
defaultPort: 443,
|
|
expectErr: "address [host.example.com:443: missing ']' in address",
|
|
},
|
|
{
|
|
name: "invalid host with underscores",
|
|
input: "___.example.com:1234",
|
|
defaultPort: 443,
|
|
expectErr: `host "___.example.com" is not a valid hostname or IP address`,
|
|
},
|
|
{
|
|
name: "invalid host with extra port",
|
|
input: "host.example.com:port1:port2",
|
|
defaultPort: 443,
|
|
expectErr: `host "host.example.com:port1:port2" is not a valid hostname or IP address`,
|
|
},
|
|
{
|
|
name: "hostname with upper case letters should be valid",
|
|
input: "HoSt.EXamplE.cOM",
|
|
defaultPort: 443,
|
|
expect: HostPort{Host: "HoSt.EXamplE.cOM", Port: 443},
|
|
expectEndpoint: "HoSt.EXamplE.cOM:443",
|
|
},
|
|
{
|
|
name: "unicode chars are disallowed in host names",
|
|
input: "Hello.世界🙂.com",
|
|
defaultPort: 443,
|
|
expectErr: `host "Hello.世界🙂.com" is not a valid hostname or IP address`,
|
|
},
|
|
} {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got, err := Parse(tt.input, tt.defaultPort)
|
|
if tt.expectErr == "" {
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, tt.expect, got)
|
|
assert.Equal(t, tt.expectEndpoint, got.Endpoint())
|
|
} else {
|
|
assert.EqualError(t, err, tt.expectErr)
|
|
assert.Equal(t, HostPort{}, got)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestParseFromURL(t *testing.T) {
|
|
t.Parallel()
|
|
for _, tt := range []struct {
|
|
name string
|
|
input string
|
|
defaultPort uint16
|
|
expectErr string
|
|
expect HostPort
|
|
// HostPort.Endpoint() returns a properly constructed endpoint. The normalization provided by ParseFromURL()
|
|
// expects that the resulting HostPort.Endpoint() will be called to normalize several special cases, especially
|
|
// for IPv6.
|
|
expectEndpoint string
|
|
}{
|
|
// First set of valid passthrough tests to Parse()
|
|
// Matches the above test table, minus any test that would not url.Parse(input) properly
|
|
{
|
|
name: "plain IPv4",
|
|
input: "http://127.0.0.1",
|
|
defaultPort: 443,
|
|
expect: HostPort{Host: "127.0.0.1", Port: 443},
|
|
expectEndpoint: "127.0.0.1:443",
|
|
},
|
|
{
|
|
name: "IPv4 with port",
|
|
input: "http://127.0.0.1:8443",
|
|
defaultPort: 443,
|
|
expect: HostPort{Host: "127.0.0.1", Port: 8443},
|
|
expectEndpoint: "127.0.0.1:8443",
|
|
},
|
|
{
|
|
name: "IPv4 as IPv6 in brackets with port",
|
|
input: "http://[::127.0.0.1]:8443",
|
|
defaultPort: 443,
|
|
expect: HostPort{Host: "::127.0.0.1", Port: 8443},
|
|
expectEndpoint: "[::127.0.0.1]:8443",
|
|
},
|
|
{
|
|
name: "IPv6 with port",
|
|
input: "http://[2001:db8::ffff]:8443",
|
|
defaultPort: 443,
|
|
expect: HostPort{Host: "2001:db8::ffff", Port: 8443},
|
|
expectEndpoint: "[2001:db8::ffff]:8443",
|
|
},
|
|
{
|
|
name: "plain hostname",
|
|
input: "http://host.example.com",
|
|
defaultPort: 443,
|
|
expect: HostPort{Host: "host.example.com", Port: 443},
|
|
expectEndpoint: "host.example.com:443",
|
|
},
|
|
{
|
|
name: "plain hostname with dash",
|
|
input: "http://host-dev.example.com",
|
|
defaultPort: 443,
|
|
expect: HostPort{Host: "host-dev.example.com", Port: 443},
|
|
expectEndpoint: "host-dev.example.com:443",
|
|
},
|
|
{
|
|
name: "hostname with port",
|
|
input: "http://host.example.com:8443",
|
|
defaultPort: 443,
|
|
expect: HostPort{Host: "host.example.com", Port: 8443},
|
|
expectEndpoint: "host.example.com:8443",
|
|
},
|
|
{
|
|
name: "hostname without dots",
|
|
input: "http://localhost",
|
|
defaultPort: 443,
|
|
expect: HostPort{Host: "localhost", Port: 443},
|
|
expectEndpoint: "localhost:443",
|
|
},
|
|
{
|
|
name: "hostname and port without dots",
|
|
input: "http://localhost:8443",
|
|
defaultPort: 443,
|
|
expect: HostPort{Host: "localhost", Port: 8443},
|
|
expectEndpoint: "localhost:8443",
|
|
},
|
|
{
|
|
name: "http://invalid empty string",
|
|
input: "",
|
|
defaultPort: 443,
|
|
expectErr: `host "" is not a valid hostname or IP address`,
|
|
},
|
|
{
|
|
name: "invalid host with underscores",
|
|
input: "http://___.example.com:1234",
|
|
defaultPort: 443,
|
|
expectErr: `host "___.example.com" is not a valid hostname or IP address`,
|
|
},
|
|
|
|
{
|
|
name: "hostname with upper case letters should be valid",
|
|
input: "https://HoSt.EXamplE.cOM",
|
|
defaultPort: 443,
|
|
expect: HostPort{Host: "HoSt.EXamplE.cOM", Port: 443},
|
|
expectEndpoint: "HoSt.EXamplE.cOM:443",
|
|
},
|
|
{
|
|
name: "unicode chars are disallowed in host names",
|
|
input: "https://Hello.世界🙂.com",
|
|
defaultPort: 443,
|
|
expectErr: `host "Hello.世界🙂.com" is not a valid hostname or IP address`,
|
|
},
|
|
// new tests for new functionality
|
|
{
|
|
name: "IPv6 with brackets but without port will strip brackets to create HostPort{}, which will add brackets when HostPort.Endpoint() is called",
|
|
input: "http://[2001:db8::ffff]",
|
|
defaultPort: 443,
|
|
expect: HostPort{Host: "2001:db8::ffff", Port: 443},
|
|
expectEndpoint: "[2001:db8::ffff]:443",
|
|
},
|
|
{
|
|
name: "IPv6 without brackets and without port will create HostPort{}, which will add brackets when HostPort.Endpoint() is called",
|
|
input: "http://2001:db8::1234",
|
|
defaultPort: 443,
|
|
expect: HostPort{Host: "2001:db8::1234", Port: 443},
|
|
expectEndpoint: "[2001:db8::1234]:443",
|
|
},
|
|
{
|
|
name: "IPv6 without brackets and without port with path create HostPort{}, which will add brackets when HostPort.Endpoint() is called",
|
|
input: "https://0:0:0:0:0:0:0:1/some/fake/path",
|
|
defaultPort: 443,
|
|
expect: HostPort{Host: "0:0:0:0:0:0:0:1", Port: 443},
|
|
expectEndpoint: "[0:0:0:0:0:0:0:1]:443",
|
|
},
|
|
{
|
|
name: "IPv6 with mismatched leading bracket will err on bracket",
|
|
input: "https://[[::1]/some/fake/path",
|
|
defaultPort: 443,
|
|
expect: HostPort{Host: "::1", Port: 443},
|
|
expectEndpoint: "[::1]:443",
|
|
},
|
|
} {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
urlToProcess, err := url.Parse(tt.input)
|
|
require.NoError(t, err, "ParseFromURL expects a valid url.URL, parse errors here are not valuable")
|
|
|
|
got, err := ParseFromURL(urlToProcess, tt.defaultPort)
|
|
if tt.expectErr == "" {
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, tt.expect, got)
|
|
assert.Equal(t, tt.expectEndpoint, got.Endpoint())
|
|
} else {
|
|
assert.EqualError(t, err, tt.expectErr)
|
|
assert.Equal(t, HostPort{}, got)
|
|
}
|
|
})
|
|
}
|
|
}
|