package hosts import ( "errors" "fmt" "net" "net/url" "strconv" "strings" ) type Target struct { Host string Port int } func (t *Target) String() string { return fmt.Sprintf("%s:%d", t.Host, t.Port) } func parseURL(host string) (string, int, error) { url, err := url.Parse(host) if err != nil { return "", 0, fmt.Errorf("certlib/hosts: invalid host: %s", host) } if strings.ToLower(url.Scheme) != "https" { return "", 0, errors.New("certlib/hosts: only https scheme supported") } if url.Port() == "" { return url.Hostname(), 443, nil } port, err := strconv.ParseInt(url.Port(), 10, 16) if err != nil { return "", 0, fmt.Errorf("certlib/hosts: invalid port: %s", url.Port()) } return url.Hostname(), int(port), nil } func parseHostPort(host string) (string, int, error) { host, sport, err := net.SplitHostPort(host) if err == nil { port, err := strconv.ParseInt(sport, 10, 16) if err != nil { return "", 0, fmt.Errorf("certlib/hosts: invalid port: %s", sport) } return host, int(port), nil } return host, 443, nil } func ParseHost(host string) (*Target, error) { host, port, err := parseURL(host) if err == nil { return &Target{Host: host, Port: port}, nil } host, port, err = parseHostPort(host) if err == nil { return &Target{Host: host, Port: port}, nil } return nil, fmt.Errorf("certlib/hosts: invalid host: %s", host) } func ParseHosts(hosts ...string) ([]*Target, error) { targets := make([]*Target, 0, len(hosts)) for _, host := range hosts { target, err := ParseHost(host) if err != nil { return nil, err } targets = append(targets, target) } return targets, nil }