Skip to content

Commit

Permalink
updates endpoint validation of hostname to allow port number to be sp…
Browse files Browse the repository at this point in the history
…ecified (#279)
  • Loading branch information
skotambkar authored Apr 7, 2021
1 parent f1e1b09 commit 87b7445
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 3 deletions.
42 changes: 39 additions & 3 deletions transport/http/host.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,34 @@ package http

import (
"fmt"
"net"
"strconv"
"strings"
)

// ValidateEndpointHost validates that the host string passed in is a valid RFC
// 3986 host. Returns error if the host is not valid.
func ValidateEndpointHost(host string) error {
var errors strings.Builder
labels := strings.Split(host, ".")
var hostname string
var port string
var err error

if strings.Contains(host, ":") {
hostname, port, err = net.SplitHostPort(host)
if err != nil {
errors.WriteString(fmt.Sprintf("\n endpoint %v, failed to parse, got ", host))
errors.WriteString(err.Error())
}

if !ValidPortNumber(port) {
errors.WriteString(fmt.Sprintf("port number should be in range [0-65535], got %v", port))
}
} else {
hostname = host
}

labels := strings.Split(hostname, ".")
for i, label := range labels {
if i == len(labels)-1 && len(label) == 0 {
// Allow trailing dot for FQDN hosts.
Expand All @@ -23,8 +42,12 @@ func ValidateEndpointHost(host string) error {
}
}

if len(host) > 255 {
errors.WriteString(fmt.Sprintf("\nendpoint host must be less than 255 characters, but was %d", len(host)))
if len(hostname) == 0 && len(port) != 0 {
errors.WriteString("\nendpoint host with port must not be empty")
}

if len(hostname) > 255 {
errors.WriteString(fmt.Sprintf("\nendpoint host must be less than 255 characters, but was %d", len(hostname)))
}

if len(errors.String()) > 0 {
Expand All @@ -33,6 +56,19 @@ func ValidateEndpointHost(host string) error {
return nil
}

// ValidPortNumber return if the port is valid RFC 3986 port
func ValidPortNumber(port string) bool {
i, err := strconv.Atoi(port)
if err != nil {
return false
}

if i < 0 || i > 65535 {
return false
}
return true
}

// ValidHostLabel returns if the label is a valid RFC 3986 host label.
func ValidHostLabel(label string) bool {
if l := len(label); l == 0 || l > 63 {
Expand Down
26 changes: 26 additions & 0 deletions transport/http/host_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,28 @@ import (
"testing"
)

func TestValidPortNumber(t *testing.T) {
cases := []struct {
Input string
Valid bool
}{
{Input: "123", Valid: true},
{Input: "123.0", Valid: false},
{Input: "-123", Valid: false},
{Input: "65536", Valid: false},
{Input: "0", Valid: true},
}
for i, c := range cases {
t.Run(strconv.Itoa(i), func(t *testing.T) {
valid := ValidPortNumber(c.Input)
if e, a := c.Valid, valid; e != a {
t.Errorf("expect valid %v, got %v", e, a)
}
})
}

}

func TestValidHostLabel(t *testing.T) {
cases := []struct {
Input string
Expand Down Expand Up @@ -48,6 +70,10 @@ func TestValidateEndpointHostHandler(t *testing.T) {
Input: "123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456",
Valid: false,
},
"valid host with port number": {Input: "abd.123:1234", Valid: true},
"valid host with invalid port number": {Input: "abc.123:99999", Valid: false},
"empty host with port number": {Input: ":1234", Valid: false},
"valid host with empty port number": {Input: "abc.123:", Valid: false},
}

for name, c := range cases {
Expand Down

0 comments on commit 87b7445

Please sign in to comment.