src

Go monorepo.
git clone git://code.dwrz.net/src
Log | Files | Refs

host.go (2021B)


      1 package http
      2 
      3 import (
      4 	"fmt"
      5 	"net"
      6 	"strconv"
      7 	"strings"
      8 )
      9 
     10 // ValidateEndpointHost validates that the host string passed in is a valid RFC
     11 // 3986 host. Returns error if the host is not valid.
     12 func ValidateEndpointHost(host string) error {
     13 	var errors strings.Builder
     14 	var hostname string
     15 	var port string
     16 	var err error
     17 
     18 	if strings.Contains(host, ":") {
     19 		hostname, port, err = net.SplitHostPort(host)
     20 		if err != nil {
     21 			errors.WriteString(fmt.Sprintf("\n endpoint %v, failed to parse, got ", host))
     22 			errors.WriteString(err.Error())
     23 		}
     24 
     25 		if !ValidPortNumber(port) {
     26 			errors.WriteString(fmt.Sprintf("port number should be in range [0-65535], got %v", port))
     27 		}
     28 	} else {
     29 		hostname = host
     30 	}
     31 
     32 	labels := strings.Split(hostname, ".")
     33 	for i, label := range labels {
     34 		if i == len(labels)-1 && len(label) == 0 {
     35 			// Allow trailing dot for FQDN hosts.
     36 			continue
     37 		}
     38 
     39 		if !ValidHostLabel(label) {
     40 			errors.WriteString("\nendpoint host domain labels must match \"[a-zA-Z0-9-]{1,63}\", but found: ")
     41 			errors.WriteString(label)
     42 		}
     43 	}
     44 
     45 	if len(hostname) == 0 && len(port) != 0 {
     46 		errors.WriteString("\nendpoint host with port must not be empty")
     47 	}
     48 
     49 	if len(hostname) > 255 {
     50 		errors.WriteString(fmt.Sprintf("\nendpoint host must be less than 255 characters, but was %d", len(hostname)))
     51 	}
     52 
     53 	if len(errors.String()) > 0 {
     54 		return fmt.Errorf("invalid endpoint host%s", errors.String())
     55 	}
     56 	return nil
     57 }
     58 
     59 // ValidPortNumber returns whether the port is valid RFC 3986 port.
     60 func ValidPortNumber(port string) bool {
     61 	i, err := strconv.Atoi(port)
     62 	if err != nil {
     63 		return false
     64 	}
     65 
     66 	if i < 0 || i > 65535 {
     67 		return false
     68 	}
     69 	return true
     70 }
     71 
     72 // ValidHostLabel returns whether the label is a valid RFC 3986 host abel.
     73 func ValidHostLabel(label string) bool {
     74 	if l := len(label); l == 0 || l > 63 {
     75 		return false
     76 	}
     77 	for _, r := range label {
     78 		switch {
     79 		case r >= '0' && r <= '9':
     80 		case r >= 'A' && r <= 'Z':
     81 		case r >= 'a' && r <= 'z':
     82 		case r == '-':
     83 		default:
     84 			return false
     85 		}
     86 	}
     87 
     88 	return true
     89 }